/**
 * Phân tích hợp tuổi theo nhiều phương pháp (đa mode).
 *
 * Combines:
 *   1. Tử Vi truyền thống (compat.ts) — 4 sub: Can, Chi, Ngũ Hành, Cung Phi
 *   2. Cung Hoàng Đạo phương Tây (western-zodiac.ts)
 *   3. Bát Tự nhật chủ (bat-tu.ts) — chỉ tính khi có ngày + giờ sinh đầy đủ
 *   4. Thần số học Life Path (numerology.ts)
 *
 * Weights theo mode:
 *   - marriage: 35 / 20 / 25 / 20 (đa diện cảm xúc + tâm linh)
 *   - business: 50 / 15 / 20 / 15 (nặng Mệnh + Cung Phi truyền thống)
 *
 * Total = weighted average. Khi method 3 không có (thiếu giờ),
 * trọng số được phân bổ lại cho 3 method còn.
 */

import { compatReport, type Person } from "./compat";
import { westernFromDate, westernCompat } from "./western-zodiac";
import { computeBatTu, dayMaster } from "./bat-tu";
import { lifePath } from "./numerology";

export type DeepCompatInput = {
  birthDate: string; // ISO YYYY-MM-DD
  gender: "Nam" | "Nữ";
  hour?: number; // 0-23, optional
  fullName?: string; // optional for numerology label
};

export type MethodResult = {
  key: string;
  label: string;
  score: number; // 0-100
  weight: number;
  summary: string;
  details?: Array<{ label: string; score: number; max: number; note: string }>;
};

export type DeepCompat = {
  totalScore: number; // 0-100 weighted average
  rating: "rất hợp" | "hợp" | "bình hoà" | "cần lưu ý" | "khắc kỵ";
  methods: MethodResult[];
  hint: string;
  hasHour: boolean;
};

// =============================================================
// Helpers per method
// =============================================================

const ELEMENT_SINH: Record<string, string> = {
  Mộc: "Hỏa",
  Hỏa: "Thổ",
  Thổ: "Kim",
  Kim: "Thuỷ",
  Thuỷ: "Mộc",
};

const ELEMENT_KHAC: Record<string, string> = {
  Mộc: "Thổ",
  Thổ: "Thuỷ",
  Thuỷ: "Hỏa",
  Hỏa: "Kim",
  Kim: "Mộc",
};

function elementRelation(a: string, b: string): { kind: string; score: number } {
  if (a === b) return { kind: "tỉ hoà (cùng hành)", score: 70 };
  if (ELEMENT_SINH[a] === b) return { kind: `${a} sinh ${b} — hỗ trợ`, score: 90 };
  if (ELEMENT_SINH[b] === a) return { kind: `${b} sinh ${a} — được nuôi dưỡng`, score: 85 };
  if (ELEMENT_KHAC[a] === b) return { kind: `${a} khắc ${b} — bất lợi cho ${b}`, score: 35 };
  if (ELEMENT_KHAC[b] === a) return { kind: `${b} khắc ${a} — bất lợi cho ${a}`, score: 35 };
  return { kind: "trung tính", score: 60 };
}

// Numerology Life Path compatibility table (giản lược, dựa trên numerology compatibility theory)
const LIFE_PATH_COMPAT: Record<number, number[]> = {
  1: [3, 5, 6],
  2: [4, 6, 8, 9],
  3: [1, 5, 7, 9],
  4: [2, 7, 8],
  5: [1, 3, 7, 9],
  6: [1, 2, 8, 9],
  7: [3, 4, 5],
  8: [2, 4, 6],
  9: [2, 3, 5, 6],
};

const LIFE_PATH_CHALLENGE: Record<number, number[]> = {
  1: [4, 8],
  2: [1, 5],
  3: [4, 8],
  4: [3, 5],
  5: [2, 4, 6],
  6: [5, 7],
  7: [1, 6, 8],
  8: [1, 3, 7],
  9: [1, 4],
};

function lifePathCompat(lp1: number, lp2: number): { score: number; reason: string } {
  if (lp1 === lp2)
    return {
      score: 75,
      reason: `Cả hai đều Life Path ${lp1} — hiểu nhau sâu nhưng cần đa dạng để không nhàm.`,
    };
  if (LIFE_PATH_COMPAT[lp1]?.includes(lp2))
    return {
      score: 90,
      reason: `Life Path ${lp1} & ${lp2} là cặp hỗ trợ tự nhiên — tính cách bù trừ.`,
    };
  if (LIFE_PATH_CHALLENGE[lp1]?.includes(lp2))
    return {
      score: 40,
      reason: `Life Path ${lp1} & ${lp2} là cặp đối lập — cần nhiều giao tiếp và thoả hiệp.`,
    };
  return {
    score: 65,
    reason: `Life Path ${lp1} & ${lp2} trung tính — phụ thuộc nhiều vào yếu tố khác.`,
  };
}

// =============================================================
// Main aggregator
// =============================================================

export function deepCompat(
  p1: DeepCompatInput,
  p2: DeepCompatInput,
  mode: "marriage" | "business" = "marriage"
): DeepCompat {
  const d1 = new Date(p1.birthDate);
  const d2 = new Date(p2.birthDate);
  if (isNaN(d1.getTime()) || isNaN(d2.getTime())) {
    throw new Error("Invalid date");
  }

  const hasHour = p1.hour !== undefined && p2.hour !== undefined;
  const methods: MethodResult[] = [];

  // Weight tables theo mode
  const W = {
    marriage: { trad: 35, west: 20, batu: 25, num: 20 },
    business: { trad: 50, west: 15, batu: 20, num: 15 },
  }[mode];

  // -----------------------------------------------------------
  // Method 1: Tử Vi truyền thống (4 sub-factors)
  // -----------------------------------------------------------
  const person1: Person = { year: d1.getFullYear(), gender: p1.gender === "Nam" ? "nam" : "nu" };
  const person2: Person = { year: d2.getFullYear(), gender: p2.gender === "Nam" ? "nam" : "nu" };
  const traditional = compatReport(person1, person2, mode);
  methods.push({
    key: "traditional",
    label: "Tử Vi truyền thống",
    score: traditional.total,
    weight: W.trad,
    summary: `${traditional.rating} (${traditional.total}/100). ${traditional.hint}`,
    details: traditional.factors.map((f) => ({
      label: f.label,
      score: f.score,
      max: f.max,
      note: f.reason,
    })),
  });

  // -----------------------------------------------------------
  // Method 2: Cung Hoàng Đạo phương Tây
  // -----------------------------------------------------------
  const w1 = westernFromDate(d1.getMonth() + 1, d1.getDate());
  const w2 = westernFromDate(d2.getMonth() + 1, d2.getDate());
  const western = westernCompat(w1.slug, w2.slug);
  if (western) {
    methods.push({
      key: "western",
      label: "Cung Hoàng Đạo phương Tây",
      score: western.totalScore,
      weight: W.west,
      summary: `${w1.name} (${w1.element}) ↔ ${w2.name} (${w2.element}) — ${western.rating} (${western.totalScore}/100).`,
      details: [
        {
          label: "Element score",
          score: western.elementScore,
          max: 100,
          note: western.notes[0] ?? "",
        },
        {
          label: "Modality score",
          score: western.modalityScore,
          max: 100,
          note: western.notes[1] ?? `Modality ${w1.modality} ↔ ${w2.modality}`,
        },
      ],
    });
  }

  // -----------------------------------------------------------
  // Method 3: Bát Tự nhật chủ (only if both have hour)
  // -----------------------------------------------------------
  if (hasHour) {
    const bt1 = computeBatTu(d1.getFullYear(), d1.getMonth() + 1, d1.getDate(), p1.hour!);
    const bt2 = computeBatTu(d2.getFullYear(), d2.getMonth() + 1, d2.getDate(), p2.hour!);
    const dm1 = dayMaster(bt1);
    const dm2 = dayMaster(bt2);
    const rel = elementRelation(dm1.element, dm2.element);
    methods.push({
      key: "bat-tu",
      label: "Bát Tự nhật chủ",
      score: rel.score,
      weight: W.batu,
      summary: `Nhật chủ ${dm1.stem} (${dm1.element}) ↔ ${dm2.stem} (${dm2.element}) — ${rel.kind}.`,
      details: [
        {
          label: "Day Master 1",
          score: 0,
          max: 0,
          note: `${dm1.stem} ${dm1.yinYang} (${dm1.element})`,
        },
        {
          label: "Day Master 2",
          score: 0,
          max: 0,
          note: `${dm2.stem} ${dm2.yinYang} (${dm2.element})`,
        },
        { label: "Quan hệ", score: rel.score, max: 100, note: rel.kind },
      ],
    });
  }

  // -----------------------------------------------------------
  // Method 4: Thần số học Life Path
  // -----------------------------------------------------------
  const lp1 = lifePath(d1.getFullYear(), d1.getMonth() + 1, d1.getDate());
  const lp2 = lifePath(d2.getFullYear(), d2.getMonth() + 1, d2.getDate());
  const lpCompat = lifePathCompat(lp1, lp2);
  methods.push({
    key: "numerology",
    label: "Thần số học Life Path",
    score: lpCompat.score,
    weight: W.num,
    summary: `Life Path ${lp1} ↔ ${lp2} — điểm ${lpCompat.score}/100. ${lpCompat.reason}`,
    details: [
      { label: "Life Path 1", score: 0, max: 0, note: `Số chủ đạo ${lp1}` },
      { label: "Life Path 2", score: 0, max: 0, note: `Số chủ đạo ${lp2}` },
      { label: "Compat", score: lpCompat.score, max: 100, note: lpCompat.reason },
    ],
  });

  // -----------------------------------------------------------
  // Aggregate (weighted average, redistribute if method missing)
  // -----------------------------------------------------------
  const totalWeight = methods.reduce((s, m) => s + m.weight, 0);
  const weightedSum = methods.reduce((s, m) => s + m.score * m.weight, 0);
  const totalScore = Math.round(weightedSum / totalWeight);

  let rating: DeepCompat["rating"] = "bình hoà";
  if (totalScore >= 85) rating = "rất hợp";
  else if (totalScore >= 70) rating = "hợp";
  else if (totalScore >= 55) rating = "bình hoà";
  else if (totalScore >= 40) rating = "cần lưu ý";
  else rating = "khắc kỵ";

  const hintMap = {
    marriage: {
      high: "Cặp đôi rất hợp ở nhiều bình diện. Tình cảm sâu, nền tảng vững. Việc còn lại là vun đắp và phát triển cùng nhau.",
      good: "Cặp đôi hợp tốt. Có một vài yếu tố cần lưu tâm nhưng tổng thể nền tảng vững.",
      mid: "Mức trung bình — sự thấu hiểu và giao tiếp quan trọng hơn các yếu tố tử vi.",
      low: "Có một số yếu tố khắc. Cần kiên nhẫn, hoá giải bằng phong thuỷ + giao tiếp chân thành.",
      bad: "Nhiều yếu tố khắc kỵ. Cân nhắc kỹ trước khi gắn bó dài hạn — hoặc cần các biện pháp hoá giải mạnh.",
    },
    business: {
      high: "Cặp đôi đối tác rất hợp về Mệnh và Cung Phi. Hợp tác lâu dài thuận lợi, tài lộc tương trợ.",
      good: "Đối tác hợp tốt. Phân vai rõ ràng và tin tưởng nhau là chìa khoá để cộng sinh.",
      mid: "Mức bình hoà. Cần thoả thuận rõ ràng về vốn-trách nhiệm-lợi nhuận và bám sát kế hoạch.",
      low: "Có yếu tố xung khắc về Mệnh hoặc Cung. Nếu hợp tác, cần hợp đồng chặt + vai trò không chồng chéo.",
      bad: "Nhiều yếu tố khắc kỵ. Cân nhắc kỹ trước khi góp vốn — dễ phát sinh tranh chấp hoặc thất hoà.",
    },
  }[mode];

  const hint =
    totalScore >= 85
      ? hintMap.high
      : totalScore >= 70
        ? hintMap.good
        : totalScore >= 55
          ? hintMap.mid
          : totalScore >= 40
            ? hintMap.low
            : hintMap.bad;

  return {
    totalScore,
    rating,
    methods,
    hint,
    hasHour,
  };
}

/** Backward-compat alias — giữ cho code cũ gọi tên cũ. */
export function deepMarriageCompat(p1: DeepCompatInput, p2: DeepCompatInput): DeepCompat {
  return deepCompat(p1, p2, "marriage");
}
