import client from "@/lib/client";
import config from "@/lib/config";
import Memory from "@/lib/memory";
import { readFileSync } from "node:fs";
import { EOL } from "node:os";
import { isMainThread, workerData } from "node:worker_threads";

const cityList = [
  "016010",
  "020010",
  "030010",
  "040010",
  "050010",
  "060010",
  "070010",
  "080010",
  "090010",
  "100010",
  "110010",
  "120010",
  "130010",
  "140010",
  "150010",
  "160010",
  "170010",
  "180010",
  "190010",
  "200010",
  "210010",
  "220010",
  "230010",
  "240010",
  "250010",
  "260010",
  "270000",
  "280010",
  "290010",
  "300010",
  "310010",
  "320010",
  "330010",
  "340010",
  "350010",
  "360010",
  "370000",
  "380010",
  "390010",
  "400010",
  "410010",
  "420010",
  "430010",
  "440010",
  "450010",
  "460010",
  "471010",
];

if (
  !isMainThread &&
  typeof workerData === "string" &&
  workerData.startsWith("scheduledWeatherNotice")
) {
  console.log("天気予報の投稿を行います");

  try {
    let provisionalUeuse;
    let success = false;

    for (let attempt = 1; attempt <= config.ueuse.maxRetries; attempt++) {
      const provisionalText = [];
      provisionalText.push(`${workerData.endsWith("Tomorrow")
        ? "明日"
        : "今日"}の天気`);
      provisionalText.push("※タイムラインが埋まるため返信に記載しています。");
      provisionalUeuse = await client.request("ueuse/create", {
        text: provisionalText.join(EOL),
      });

      if (provisionalUeuse.success) {
        success = true;
        break;
      }

      console.warn(`天気仮投稿に失敗しました (試行 ${attempt}/${config.ueuse.maxRetries}):`, provisionalUeuse.error_code);
      if (attempt < config.ueuse.maxRetries) {
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
    }

    if (!success || !provisionalUeuse?.success) {
      console.error("天気仮投稿の全試行に失敗したため、終了します。");
      process.exit(1);
    }

    console.log("天気仮投稿:", provisionalUeuse.uniqid);

    await weatherReply(provisionalUeuse.uniqid, workerData.endsWith("Tomorrow"));
    process.exit(0);
  } catch (err: any) {
    console.error("message" in err
      ? err.message
      : err);
    process.exit(1);
  }
}

export async function weatherReply(uniqid: string, isTomorrow: boolean) {
  // インデックス
  const aboutFullLength = 3100;
  const mem = Memory.memory;
  const splitCount = Math.round(aboutFullLength / mem.max_length);
  const total = cityList.length;
  const chunkSizes = Array(splitCount).fill(0).map((_, i) =>
    Math.floor((total + i) / splitCount)
  );

  // 分割インデックス
  let start = 0;
  const ranges: [number, number][] = chunkSizes.map(size => {
    const range: [number, number] = [start, start + size];
    start += size;
    return range;
  });

  // 配列作成
  const weatherResults = Array(splitCount).fill("");

  // package.json取得
  const packageJson = JSON.parse(readFileSync(`${import.meta.dirname}/../../package.json`, "utf-8"));

  // 天気取得
  for (let chunkIndex = 0; chunkIndex < splitCount; chunkIndex++) {
    const range = ranges[chunkIndex];
    if (!range) continue;

    const [chunkStart, chunkEnd] = range;

    for (let i = chunkStart; i < chunkEnd; i++) {
      const res = await fetch(`https://weather.tsukumijima.net/api/forecast/city/${cityList[i]}`, {
        headers: {
          "User-Agent": `noticeUwuzu/${packageJson.version}`,
        },
      });

      const data = await res.json();
      const itDay = isTomorrow
        ? data.forecasts[1]
        : data.forecasts[0];

      // 天気
      const areaText = [];
      areaText.push(`【${data.location.city}】`);
      areaText.push(`⛅天気: ${itDay.telop ?? "取得できませんでした"}`);
      areaText.push(`🔆最高気温: ${itDay.temperature.max.celsius
        ? `${itDay.temperature.max.celsius}℃`
        : "取得できませんでした"}`);
      areaText.push(`🔅最低気温: ${itDay.temperature.min.celsius
        ? `${itDay.temperature.min.celsius}℃`
        : "取得できませんでした"}`);
      areaText.push(`☔降水確率: ${
        itDay.chanceOfRain.T06_12 !== null &&
        itDay.chanceOfRain.T06_12 !== "--%"
          ? itDay.chanceOfRain.T06_12
          : "取得できませんでした"}`);
      weatherResults[chunkIndex] += areaText.join(EOL) + EOL.repeat(2);
    }
  }

  // 分割投稿
  for (let i = 0; i < splitCount; i++) {
    let replyUeuse;
    let success = false;

    for (let attempt = 1; attempt <= config.ueuse.maxRetries; attempt++) {
      replyUeuse = await client.request("ueuse/create", {
        text: weatherResults[i].trim(),
        replyid: uniqid,
      });

      if (replyUeuse.success) {
        success = true;
        break;
      }

      console.warn(`天気返信に失敗しました (試行 ${attempt}/${config.ueuse.maxRetries}):`, replyUeuse.error_code);
      if (attempt < config.ueuse.maxRetries) {
        await new Promise(resolve => setTimeout(resolve, config.ueuse.retryInterval));
      }
    }

    if (!success || !replyUeuse?.success) {
      console.error("天気返信の全試行に失敗したため、終了します。");
      process.exit(1);
    }

    console.log("天気返信:", replyUeuse.uniqid);
  }
}