import { GameState, OptionId, PerkId } from "./types";
import {
  catchRateBest,
  catchRateGood,
  choicePerGold,
  choicePerSilver,
  levelTimeBest,
  levelTimeGood,
  missesBest,
  missesGood,
  upPerGold,
  upPerSilver,
} from "./pure_functions";
import { t } from "./i18n/i18n";
import { icons } from "./loadGameData";
import { requiredAsyncAlert } from "./asyncAlert";
import {
  escapeAttribute,
  getPossibleUpgrades,
  levelsListHTMl,
  max_levels,
  pickedUpgradesHTMl,
  renderMaxLevel,
  upgradeLevelAndMaxDisplay,
} from "./game_utils";
import { getFirstUnlockable, getNearestUnlockHTML } from "./openScorePanel";
import { isOptionOn } from "./options";
import { getWorstFPSAndReset } from "./fps";
import {
  getCurrentMaxCoins,
  getSettingValue,
  setSettingValue,
} from "./settings";
import { toast } from "./toast";

export async function openUpgradesPicker(gameState: GameState) {
  if (gameState.perks.chill) return;
  const catchRate =
    gameState.levelCoughtCoins / (gameState.levelSpawnedCoins || 1);

  let medals = [];
  let upgradePoints = 1;
  let extraChoices = 0;

  let hasMedals = 0;

  function challengeResult(
    name: String,
    description: String,
    medal: "gold" | "silver" | "no",
  ) {
    let choices = 0,
      up = 0;
    if (medal === "gold") {
      choices += choicePerGold;
      up += upPerGold;
    } else if (medal === "silver") {
      choices += choicePerSilver;
      up += upPerSilver;
    }
    if (medal !== "no") {
      hasMedals++;
    }

    extraChoices += choices;
    upgradePoints += up;
    medals.push(`<div  class="upgrade" data-tooltip="${escapeAttribute(description)}">
                        ${icons["icon:" + medal + "_medal"]}
                        <p>
                        <strong>${name}</strong><br/>
                        ${
                          up || choices
                            ? t("level_up.challenges.gain", { up, choices })
                            : t("level_up.challenges.no_gain")
                        }
                      
                        </p> 
                    </div>`);
  }

  challengeResult(
    t("level_up.challenges.levelTime.name", {
      value: Math.ceil(gameState.levelTime / 1000),
    }),
    t("level_up.challenges.levelTime.description", {
      silver: levelTimeGood,
      gold: levelTimeBest,
    }),
    (gameState.levelTime < levelTimeBest * 1000 && "gold") ||
      (gameState.levelTime < levelTimeGood * 1000 && "silver") ||
      "no",
  );

  challengeResult(
    t("level_up.challenges.catchRateGood.name", {
      value: Math.floor(catchRate * 100),
      caught: gameState.levelCoughtCoins,
      total: gameState.levelSpawnedCoins,
    }),
    t("level_up.challenges.catchRateGood.description", {
      silver: catchRateGood,
      gold: catchRateBest,
    }),
    (catchRate > catchRateBest / 100 && "gold") ||
      (catchRate > catchRateGood / 100 && "silver") ||
      "no",
  );

  challengeResult(
    gameState.levelMisses
      ? t("level_up.challenges.levelMisses.name", {
          value: gameState.levelMisses,
        })
      : t("level_up.challenges.levelMisses.none"),
    t("level_up.challenges.levelMisses.description", {
      silver: missesGood,
      gold: missesBest,
    }),
    (gameState.levelMisses < missesBest && "gold") ||
      (gameState.levelMisses < missesGood && "silver") ||
      "no",
  );

  if (hasMedals == 0) {
    medals.length = 0;
  } else if (hasMedals == 1) {
    medals.unshift(t("level_up.challenges.earned_medal", { count: hasMedals }));
  } else {
    medals.unshift(
      t("level_up.challenges.earned_medal_plural", { count: hasMedals }),
    );
  }

  let sorted = getPossibleUpgrades(gameState)
    .map((u) => ({
      ...u,
      score: Math.random() + (gameState.lastOffered[u.id] || 0),
    }))
    .sort((a, b) => a.score - b.score)
    .filter((u) => gameState.perks[u.id] < u.max + gameState.perks.limitless);
  let recommendation = settingsChangeRecommendations();
  while (true && !gameState.perks.chill) {
    // refresh the list if you pick extra one_more_choice
    const offered = sorted.slice(
      0,
      3 + extraChoices + gameState.perks.one_more_choice,
    );
    offered.forEach((u) => {
      dontOfferTooSoon(gameState, u.id);
    });

    const unlockable = getFirstUnlockable(gameState);
    let unlockRelatedUpgradesOffered = 0;

    const upgradesActions = offered.map((u) => {
      let unlockHint = "";
      let className = "";
      if (isOptionOn("level_unlocks_hints")) {
        if (unlockable?.forbidden?.includes(u.id) && !gameState.perks[u.id]) {
          unlockRelatedUpgradesOffered++;
          className += " forbidden";
          unlockHint = t("level_up.forbidden", {
            levelName: unlockable?.l.name || "",
          });
        }
        if (unlockable?.required?.includes(u.id) && !gameState.perks[u.id]) {
          unlockRelatedUpgradesOffered++;
          className += " required";
          unlockHint = t("level_up.required", {
            levelName: unlockable?.l.name || "",
          });
        }
      }
      return {
        value: u.id,
        disabled: gameState.perks[u.id] >= u.max + gameState.perks.limitless,
        text:
          u.name +
          (gameState.perks[u.id]
            ? upgradeLevelAndMaxDisplay(u, gameState)
            : ""),
        icon: icons["icon:" + u.id],
        help: u.help(gameState.perks[u.id] || 1),
        tooltip: unlockHint + u.fullHelp(gameState.perks[u.id] || 1),
        className,
        actionLabel: gameState.perks[u.id] ? "upgrade" : "pick",
      };
    });

    const choice = await requiredAsyncAlert<
      PerkId | { changeSettings: Record<string, any> }
    >({
      title: t("level_up.title", {
        level: gameState.currentLevel,
        max: renderMaxLevel(gameState),
      }),
      content: [
        t("level_up.upgrade_perks", {
          coins: gameState.levelCoughtCoins,
          count: upgradePoints,
        }),
        ...upgradesActions,
        levelsListHTMl(gameState, gameState.currentLevel),
        unlockRelatedUpgradesOffered ? getNearestUnlockHTML(gameState) : "",
        recommendation,
        ...medals,
        pickedUpgradesHTMl(gameState),
        `<div id="level-recording-container"></div>`,
      ],
    });

    if (applySettingsChangeReco(choice)) {
      recommendation = "";
    } else {
      upgradePoints--;
      gameState.perks[choice]++;
      gameState.runStatistics.upgrades_picked++;
      if (!upgradePoints) {
        return;
      }
    }
  }
}

export function dontOfferTooSoon(gameState: GameState, id: PerkId) {
  gameState.lastOffered[id] = Math.round(Date.now() / 1000);
}

export function applySettingsChangeReco(choice: unknown) {
  if (!choice) return;
  if (typeof choice == "object" && "changeSettings" in choice) {
    for (let key in choice.changeSettings) {
      setSettingValue(key, choice.changeSettings[key]);
    }
    toast(t("settings.suggestions.applied"));
    return true;
  }
  return false;
}
export function settingsChangeRecommendations() {
  const { worstFPS, coinsForLag } = getWorstFPSAndReset();
  const maxCoinsSetting = getSettingValue("max_coins", 2);

  if (worstFPS > 55) return "";
  if (coinsForLag > 200 && getCurrentMaxCoins() > 200) {
    // Limit the coins
    const limit = Math.floor(Math.log2(coinsForLag / 200));
    if (limit < maxCoinsSetting) {
      return {
        icon: icons["icon:slow"],
        text: t("settings.suggestions.reduce_coins", {
          max: Math.pow(2, limit) * 200,
        }),
        value: {
          changeSettings: { max_coins: limit },
        },
      };
    }
  }

  if (isOptionOn("record"))
    return {
      icon: icons["icon:slow"],
      text: t("settings.suggestions.record"),
      value: {
        changeSettings: { "breakout-settings-enable-record": false },
      },
    };

  if (isOptionOn("basic")) return "";

  if (
    isOptionOn("smooth_lighting") ||
    isOptionOn("precise_lighting") ||
    !isOptionOn("probabilistic_lighting") ||
    isOptionOn("contrast")
  )
    return {
      icon: icons["icon:slow"],
      text: t("settings.suggestions.simpler_lights"),
      value: {
        changeSettings: {
          "breakout-settings-enable-smooth_lighting": false,
          "breakout-settings-enable-precise_lighting": false,
          "breakout-settings-enable-probabilistic_lighting": true,
          "breakout-settings-enable-contrast": false,
        },
      },
    };

  if (isOptionOn("extra_bright"))
    return {
      icon: icons["icon:slow"],
      text: t("settings.suggestions.reduce_brightness"),
      value: {
        changeSettings: { "breakout-settings-enable-extra_bright": false },
      },
    };

  return {
    icon: icons["icon:slow"],
    text: t("settings.suggestions.basic_mode"),
    value: {
      changeSettings: { "breakout-settings-enable-basic": true },
    },
  };
}
