import { roundTo2 } from "@monkeytype/util/numbers";
import { Day } from "date-fns";

/**
 * Converts seconds to a human-readable string representation of time.
 * @param sec The number of seconds to convert.
 * @param alwaysShowMinutes Whether to always show minutes, even if the value is 0. Default is false.
 * @param alwaysShowHours Whether to always show hours, even if the value is 0. Default is false.
 * @param delimiter The delimiter to use between time components. Default is ":".
 * @param showSeconds Whether to show seconds. Default is true.
 * @param showDays Whether to show days. Default is false.
 * @returns A human-readable string representation of the time.
 */
export function secondsToString(
  sec: number,
  alwaysShowMinutes = false,
  alwaysShowHours = false,
  delimiter: ":" | "text" = ":",
  showSeconds = true,
  showDays = false,
): string {
  sec = Math.abs(sec);
  let days = 0;
  let hours;
  if (showDays) {
    days = Math.floor(sec / 86400);
    hours = Math.floor((sec % 86400) / 3600);
  } else {
    hours = Math.floor(sec / 3600);
  }
  const minutes = Math.floor((sec % 3600) / 60);
  const seconds = roundTo2((sec % 3600) % 60);

  let daysString;
  let hoursString;
  let minutesString;
  let secondsString;

  if (showDays) {
    days < 10 && delimiter !== "text"
      ? (daysString = "0" + days)
      : (daysString = days);
  }
  hours < 10 && delimiter !== "text"
    ? (hoursString = "0" + hours)
    : (hoursString = hours);
  minutes < 10 && delimiter !== "text"
    ? (minutesString = "0" + minutes)
    : (minutesString = minutes);
  seconds < 10 &&
  (minutes > 0 || hours > 0 || alwaysShowMinutes) &&
  delimiter !== "text"
    ? (secondsString = "0" + seconds)
    : (secondsString = seconds);

  let ret = "";
  if (days > 0 && showDays) {
    ret += daysString;
    if (delimiter === "text") {
      if (days === 1) {
        ret += " day ";
      } else {
        ret += " days ";
      }
    } else {
      ret += delimiter;
    }
  }
  if (hours > 0 || alwaysShowHours) {
    ret += hoursString;
    if (delimiter === "text") {
      if (hours === 1) {
        ret += " hour ";
      } else {
        ret += " hours ";
      }
    } else {
      ret += delimiter;
    }
  }
  if (minutes > 0 || hours > 0 || alwaysShowMinutes) {
    ret += minutesString;
    if (delimiter === "text") {
      if (minutes === 1) {
        ret += " minute ";
      } else {
        ret += " minutes ";
      }
    } else if (showSeconds) {
      ret += delimiter;
    }
  }
  if (showSeconds) {
    ret += secondsString;
    if (delimiter === "text") {
      if (seconds === 1) {
        ret += " second";
      } else {
        ret += " seconds";
      }
    }
  }
  if (hours === 0 && minutes === 0 && !showSeconds && delimiter === "text") {
    ret = "less than 1 minute";
  }
  return ret.trim();
}

/*
generated by
import * as Locales from "date-fns/locale";
const result = {};
  for (const locale of Object.keys(Locales)) {
    // @ts-ignore
    const data = Locales[locale] as Locales.Locale;
    result[locale] = (data.options?.weekStartsOn as number) % 7;
  }
  */

const weekStartsOnFallback: Record<string, Day> = {
  af: 0,
  ar: 6,
  arDZ: 0,
  arEG: 0,
  arMA: 1,
  arSA: 0,
  arTN: 1,
  az: 1,
  be: 1,
  beTarask: 1,
  bg: 1,
  bn: 0,
  bs: 1,
  ca: 1,
  ckb: 0,
  cs: 1,
  cy: 0,
  da: 1,
  de: 1,
  deAT: 1,
  el: 1,
  enAU: 1,
  enCA: 0,
  enGB: 1,
  enIE: 1,
  enIN: 1,
  enNZ: 1,
  enUS: 0,
  enZA: 0,
  eo: 1,
  es: 1,
  et: 1,
  eu: 1,
  faIR: 6,
  fi: 1,
  fr: 1,
  frCA: 0,
  frCH: 1,
  fy: 1,
  gd: 0,
  gl: 1,
  gu: 1,
  he: 0,
  hi: 0,
  hr: 1,
  ht: 1,
  hu: 1,
  hy: 1,
  id: 1,
  is: 1,
  it: 1,
  itCH: 1,
  ja: 0,
  jaHira: 0,
  ka: 1,
  kk: 1,
  km: 0,
  kn: 1,
  ko: 0,
  lb: 1,
  lt: 1,
  lv: 1,
  mk: 1,
  mn: 1,
  ms: 1,
  mt: 1,
  nb: 1,
  nl: 1,
  nlBE: 1,
  nn: 1,
  oc: 1,
  pl: 1,
  pt: 1,
  ptBR: 0,
  ro: 1,
  ru: 1,
  se: 1,
  sk: 1,
  sl: 1,
  sq: 1,
  sr: 1,
  srLatn: 1,
  sv: 1,
  ta: 1,
  te: 0,
  th: 0,
  tr: 1,
  ug: 0,
  uk: 1,
  uz: 1,
  uzCyrl: 1,
  vi: 1,
  zhCN: 1,
  zhHK: 0,
  zhTW: 1,
};

export function getFirstDayOfTheWeek(): Day {
  if (navigator.language === undefined || navigator.language === null) {
    return 0;
  }

  const locale = new Intl.Locale(navigator.language);
  if (locale === undefined || locale === null) {
    return 0; //sunday
  }

  //modern browsers support `weekInfo` or `getWeekInfo()`
  if ("weekInfo" in locale) {
    // @ts-expect-error weekInfo is not in the type definition
    return (locale.weekInfo.firstDay as number) % 7;
  }

  if ("getWeekInfo" in locale) {
    // @ts-expect-error getWeekInfo is not in the type definition
    // oxlint-disable-next-line no-unsafe-member-access
    return locale.getWeekInfo().firstDay % 7;
  }

  //use fallback generated from date-fns for browsers like firefox
  let fallback = weekStartsOnFallback[navigator.language.replaceAll("-", "")];
  if (fallback !== undefined) {
    return fallback;
  }

  //retry with language only
  fallback = weekStartsOnFallback[navigator.language.split("-")[0] as string];
  if (fallback !== undefined) {
    return fallback;
  }

  return 0; //start on sunday
}
