export type EntryType = "expense" | "income";

export const currencies = {
  CNY: { name: "人民币", symbol: "¥", minorUnits: 2 },
  USD: { name: "美元", symbol: "$", minorUnits: 2 },
  EUR: { name: "欧元", symbol: "€", minorUnits: 2 },
  JPY: { name: "日元", symbol: "¥", minorUnits: 0 },
  THB: { name: "泰铢", symbol: "฿", minorUnits: 2 },
  HKD: { name: "港币", symbol: "HK$", minorUnits: 2 },
} as const;

export type CurrencyCode = keyof typeof currencies;

export type ExchangeRateSource = "manual" | "system";
export type ConversionStatus = "exact" | "fallback" | "pending";

export function currencyMinorUnits(currency: CurrencyCode) {
  return currencies[currency].minorUnits;
}

export function formatCurrencyAmount(amount: number, currency: CurrencyCode, includeSymbol = true) {
  const minorUnits = currencyMinorUnits(currency);
  return new Intl.NumberFormat("zh-CN", {
    style: includeSymbol ? "currency" : "decimal",
    currency: includeSymbol ? currency : undefined,
    currencyDisplay: "narrowSymbol",
    minimumFractionDigits: minorUnits,
    maximumFractionDigits: minorUnits,
  }).format(amount / 10 ** minorUnits);
}

function decimalParts(value: string) {
  if (!/^\d+(?:\.\d+)?$/.test(value)) throw new Error("Invalid decimal rate");
  const [integer, fraction = ""] = value.split(".");
  return {
    scaled: BigInt(`${integer}${fraction}`),
    scale: 10n ** BigInt(fraction.length),
  };
}

export function calculateCnyAmount(amount: number, currency: CurrencyCode, cnyPerUnit: string) {
  if (!Number.isSafeInteger(amount) || amount <= 0) throw new Error("Invalid amount");
  const { scaled, scale } = decimalParts(cnyPerUnit);
  const divisor = (10n ** BigInt(currencyMinorUnits(currency))) * scale;
  const numerator = BigInt(amount) * scaled * 100n;
  const result = (numerator + divisor / 2n) / divisor;
  const numeric = Number(result);
  if (!Number.isSafeInteger(numeric) || numeric <= 0 || numeric > 2_147_483_647) {
    throw new Error("Converted amount is out of range");
  }
  return numeric;
}

export const ledgerThemeAccents = {
  jade: "#087f72",
  ocean: "#3478e5",
  coral: "#c94f45",
  berry: "#a84378",
  meadow: "#2f8060",
  graphite: "#526a78",
  sunrise: "#b45f4a",
  lagoon: "#177f8f",
  iris: "#7061b5",
  sky: "#327ba0",
  olive: "#64784a",
  midnight: "#47577f",
  mint: "#3c9b83",
  plum: "#895c9c",
  ember: "#b86545",
  aqua: "#258fa3",
  rose: "#c6536f",
  forest: "#4b7f5c",
} as const;

export type LedgerThemeId = keyof typeof ledgerThemeAccents;

export const ledgerIconKeys = [
  "wallet",
  "house",
  "shopping-bag",
  "shopping-cart",
  "utensils",
  "luggage",
  "map",
  "baby",
  "milk",
  "heart",
  "graduation-cap",
  "toy-brick",
  "party-popper",
  "cake",
  "gift",
  "users",
  "paint-bucket",
  "hammer",
  "sofa",
  "book-open",
  "car",
  "wrench",
] as const;

export type LedgerIconKey = typeof ledgerIconKeys[number];

export type LedgerAmountDisplayMode = "base" | "original";

export type LedgerEntry = {
  id: string;
  ownerId: string;
  ledgerIds: string[];
  type: EntryType;
  amount: number;
  currency: CurrencyCode;
  baseCurrency: CurrencyCode;
  baseAmount: number | null;
  exchangeRate: string | null;
  exchangeRateDate: string;
  exchangeRateEffectiveDate: string | null;
  exchangeRateSource: ExchangeRateSource;
  conversionStatus: ConversionStatus;
  reimbursementOfEntryId: string | null;
  categoryId: string;
  note: string;
  occurredAt: string;
  createdBy: string;
  updatedBy: string;
  createdAt: string;
  updatedAt: string;
  deletedAt: string | null;
  version: number;
};

export type SyncOperationAction = "create" | "update" | "delete";

export type SyncOperation = {
  id: string;
  userId?: string;
  ledgerIds: string[];
  entity: "entry";
  entityId: string;
  action: SyncOperationAction;
  payload: LedgerEntry;
  createdAt: string;
  syncedAt: string | null;
};
