/**
 * Tử Vi Số · Horoscope wrapper (Đại vận / Lưu niên / Lưu nguyệt / Lưu nhật)
 *
 * Wraps `iztro.horoscope(date)` into a normalized, UI-friendly shape.
 *
 * Concepts:
 *   - Đại vận (decadal): 10-year period the chart is currently in. Each
 *     palace cell has a `decadal` range (ageFrom..ageTo). The 12 đại vận
 *     together cover ~120 years of the native's life.
 *   - Lưu niên (yearly): a single year overlay. Stem/branch is the year's
 *     pillar; palace names are rotated based on which palace the year's
 *     branch falls into.
 *   - Lưu nguyệt (monthly): same idea, scoped to a single lunar month.
 *   - Lưu nhật (daily): scoped to a single lunar day.
 *
 * The Mutagen array `[Lộc, Quyền, Khoa, Kỵ]` lists the four stars that
 * receive the period's tứ hóa transformations. UI highlights these in
 * each palace cell.
 */
import { astro } from "iztro";
import { buildChart, type ChartInput } from "./engine";
import { buildAnnualHanReport, type AnnualHanReport } from "./han-vn";

export type HoroStar = {
  name: string;
  type: string;
  scope: string;
};

export type HoroscopePeriod = {
  /** "Đại Hạn" / "Lưu Niên" / "Lưu Nguyệt" / "Lưu Nhật" */
  name: string;
  /** 0..11 — index in the (Dần-first) branch order where this period is centered */
  index: number;
  /** Heavenly stem of the period */
  heavenlyStem: string;
  /** Earthly branch of the period */
  earthlyBranch: string;
  /**
   * 12 palace labels rotated so that index 0 = palace at branch Dần.
   * Used to overlay "Lưu Mệnh / Lưu Tài / …" on top of the static layout.
   */
  palaceNames: string[];
  /**
   * 4-star tứ hóa for the period: [Hóa Lộc, Hóa Quyền, Hóa Khoa, Hóa Kỵ].
   */
  mutagen: string[];
  /**
   * Period-scoped flying stars (Vận Xương / Lưu Khôi / …) per branch cell,
   * 12 arrays in branch order Dần..Sửu.
   */
  stars: HoroStar[][];
};

/** A single 10-year đại vận entry shown in the timeline. */
export type DecadalEntry = {
  /** 0..11 — branch index (Dần=0) */
  branchIndex: number;
  earthlyBranch: string;
  heavenlyStem: string;
  /** Vietnamese palace name (Mệnh / Phụ Mẫu / …) */
  palaceName: string;
  ageFrom: number;
  ageTo: number;
  /** True for the đại vận currently active on the queried date. */
  isCurrent: boolean;
};

export type Horoscope = {
  /** ISO YYYY-MM-DD the horoscope was computed for. */
  forDate: string;
  /** Vietnamese age (tuổi mụ) at `forDate`. */
  age: number;
  /** Branch sinh (zodiac, e.g. "Ngọ") of the native — derived from lunar birth year. */
  birthBranch: string;
  decadal: HoroscopePeriod;
  yearly: HoroscopePeriod;
  /** Tiểu Hạn — the 1-year period overlay rotated by age, separate from Lưu Niên. */
  ageHan: HoroscopePeriod;
  monthly: HoroscopePeriod;
  daily: HoroscopePeriod;
  /** Full 12-row table of đại vận, oldest→youngest by ageFrom. */
  decadalTimeline: DecadalEntry[];
  /** Vietnamese traditional hạn for the year of `forDate`. */
  hanVn: AnnualHanReport;
};

const BRANCH_ORDER = [
  "Dần",
  "Mão",
  "Thìn",
  "Tỵ",
  "Ngọ",
  "Mùi",
  "Thân",
  "Dậu",
  "Tuất",
  "Hợi",
  "Tý",
  "Sửu",
] as const;

/**
 * Hán → Việt mapping for the 12 earthly branches. iztro's `rawDates`
 * returns Chinese characters (子/丑/寅/...) regardless of the i18n locale,
 * so we translate them to Vietnamese for our hạn-VN module.
 */
const HAN_TO_BRANCH: Record<string, string> = {
  子: "Tý",
  丑: "Sửu",
  寅: "Dần",
  卯: "Mão",
  辰: "Thìn",
  巳: "Tỵ",
  午: "Ngọ",
  未: "Mùi",
  申: "Thân",
  酉: "Dậu",
  戌: "Tuất",
  亥: "Hợi",
};

function normalizePeriod(raw: unknown): HoroscopePeriod {
  const r = raw as Record<string, unknown>;
  const stars = (r.stars ?? []) as Array<Array<Record<string, unknown>>>;
  return {
    name: String(r.name ?? ""),
    index: Number(r.index ?? 0),
    heavenlyStem: String(r.heavenlyStem ?? ""),
    earthlyBranch: String(r.earthlyBranch ?? ""),
    palaceNames: ((r.palaceNames ?? []) as unknown[]).map((s) => String(s)),
    mutagen: ((r.mutagen ?? []) as unknown[]).map((s) => String(s)),
    stars: stars.map((row) =>
      row.map((s) => ({
        name: String(s.name ?? ""),
        type: String(s.type ?? ""),
        scope: String(s.scope ?? ""),
      }))
    ),
  };
}

/**
 * Build a horoscope snapshot for a specific date.
 *
 * @param input  Birth chart input (same as `buildChart`)
 * @param forDate ISO YYYY-MM-DD; defaults to today.
 */
export function buildHoroscope(input: ChartInput, forDate?: string): Horoscope {
  const target = forDate ?? new Date().toISOString().slice(0, 10);
  if (!/^\d{4}-\d{1,2}-\d{1,2}$/.test(target)) {
    throw new Error(`forDate phải là YYYY-MM-DD (nhận: "${target}")`);
  }

  const genderZh = input.gender === "Nam" ? "男" : "女";
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const astroAny = astro as any;
  const astrolabe =
    input.calendar === "solar"
      ? astroAny.bySolar(input.date, input.timeIndex, genderZh, true, "vi-VN")
      : astroAny.byLunar(
          input.date,
          input.timeIndex,
          genderZh,
          input.isLeapMonth ?? false,
          true,
          "vi-VN"
        );

  const horo = astrolabe.horoscope(target);

  // Build full decadal timeline from the 12 palace cells.
  const palacesRaw = (astrolabe.palaces ?? []) as Array<Record<string, unknown>>;
  const currentDecadalIndex = Number(horo.decadal?.index ?? -1);
  const timelineUnsorted: DecadalEntry[] = palacesRaw.map((p, i) => {
    const decadal = (p.decadal ?? {}) as Record<string, unknown>;
    const range = (decadal.range ?? []) as number[];
    return {
      branchIndex: i,
      earthlyBranch: BRANCH_ORDER[i] ?? "",
      heavenlyStem: String(decadal.heavenlyStem ?? ""),
      palaceName: String(p.name ?? ""),
      ageFrom: range[0] ?? 0,
      ageTo: range[1] ?? 0,
      isCurrent: i === currentDecadalIndex,
    };
  });
  const decadalTimeline = timelineUnsorted.sort((a, b) => a.ageFrom - b.ageFrom);

  // Vietnamese hạn (Tam Tai / Kim Lâu / Hoàng Ốc / fixed) need the
  // birth-branch + the year-branch + tuổi mụ. Both branches come back as
  // Chinese characters from iztro.rawDates; translate to VN before using.
  const rawDates = (astrolabe.rawDates ?? {}) as Record<string, unknown>;
  const cdate = (rawDates.chineseDate ?? {}) as Record<string, unknown>;
  const yearlyHan = (cdate.yearly ?? []) as string[];
  const birthBranch = HAN_TO_BRANCH[yearlyHan[1] ?? ""] ?? "";
  const yearBranch =
    HAN_TO_BRANCH[horo.yearly?.earthlyBranch ?? ""] ?? horo.yearly?.earthlyBranch ?? "";
  const nominalAge = Number(horo.age?.nominalAge ?? 0);
  const hanVn = buildAnnualHanReport({
    birthBranch,
    yearBranch,
    age: nominalAge,
  });

  return {
    forDate: target,
    age: nominalAge,
    birthBranch,
    decadal: normalizePeriod(horo.decadal),
    yearly: normalizePeriod(horo.yearly),
    ageHan: normalizePeriod(horo.age),
    monthly: normalizePeriod(horo.monthly),
    daily: normalizePeriod(horo.daily),
    decadalTimeline,
    hanVn,
  };
}

/** Re-export the chart builder for convenience. */
export { buildChart };
