"use client";

import { useEffect, useState } from "react";

import { useParams, useRouter } from "next/navigation";

import { getSavedMatches, SavedMatch } from "@/app/lib/kundaliMatch";

import Header from "@/app/components/layout/Header";
import Footer from "@/app/components/layout/Footer";

import "../kundli-matching.css";

/*
|--------------------------------------------------------------------------
| Types
|--------------------------------------------------------------------------
*/

type AnyObject = Record<string, any>;

/*
|--------------------------------------------------------------------------
| Ashtakoot guna definitions
|--------------------------------------------------------------------------
*/

/*
| Confirmed real response (GET /user/matching/ashtakoot): each guna is
| a top-level object keyed by its own name (tara/gana/yoni/bhakoot/
| grahamaitri/vasya/nadi/varna), and within that object:
|  - the score is under a field with that SAME key name again
|    (e.g. report.tara.tara), not "points"/"score"/"obtained"
|  - the max is "full_score", not "max"/"max_points"
|  - the per-person values are "boy_<suffix>"/"girl_<suffix>", where
|    <suffix> matches the key name for 6 of the 8 gunas but not
|    bhakoot ("boy_rasi_name") or grahamaitri ("boy_lord") — hence
|    the explicit personSuffixes list below instead of assuming a
|    single dynamic pattern.
*/

const GUNA_DEFS: {
  key: string;
  aliases: string[];
  personSuffixes: string[];
  label: string;
  subtitle: string;
  max: number;
  defaultDescription: string;
}[] = [
  { key: "varna", aliases: ["varna"], personSuffixes: ["varna"], label: "Varna", subtitle: "Work", max: 1, defaultDescription: "Natural Refinement / Work" },
  { key: "vashya", aliases: ["vashya", "vasya"], personSuffixes: ["vasya", "vashya"], label: "Vashya", subtitle: "Dominance", max: 2, defaultDescription: "Innate Giving / Attraction towards each other" },
  { key: "tara", aliases: ["tara"], personSuffixes: ["tara"], label: "Tara", subtitle: "Destiny", max: 3, defaultDescription: "Comfort - Prosperity - Health" },
  { key: "yoni", aliases: ["yoni"], personSuffixes: ["yoni"], label: "Yoni", subtitle: "Intimacy", max: 4, defaultDescription: "Intimacy" },
  { key: "maitri", aliases: ["maitri", "graha_maitri", "grahamaitri"], personSuffixes: ["lord", "grahamaitri", "maitri"], label: "Maitri", subtitle: "Mental Compatibility", max: 5, defaultDescription: "Friendship" },
  { key: "gan", aliases: ["gan", "gana"], personSuffixes: ["gana", "gan"], label: "Gan", subtitle: "Temperament", max: 6, defaultDescription: "Temperament" },
  { key: "bhakut", aliases: ["bhakut", "bhakoot"], personSuffixes: ["rasi_name", "bhakoot", "bhakut"], label: "Bhakut", subtitle: "Love", max: 7, defaultDescription: "Constructive Ability / Constructivism / Society and Couple" },
  { key: "nadi", aliases: ["nadi"], personSuffixes: ["nadi"], label: "Nadi", subtitle: "Health", max: 8, defaultDescription: "Progeny" },
];

/*
|--------------------------------------------------------------------------
| Page
|--------------------------------------------------------------------------
*/

export default function KundaliMatchDetailPage() {
  const params = useParams();
  const router = useRouter();

  const [match, setMatch] = useState<SavedMatch | null>(null);

  const [loading, setLoading] = useState(true);

  /*
  |--------------------------------------------------------------------------
  | Load Saved Match
  |--------------------------------------------------------------------------
  */

  useEffect(() => {
    const token = localStorage.getItem("token");

    if (!token) {
      router.replace("/signin");
      return;
    }

    const id = String(params?.id || "");

    if (!id) {
      setLoading(false);
      return;
    }

    const savedMatches = getSavedMatches();

    const found = savedMatches.find(
      (item) => String(item.localId) === id || String((item as any)?.apiId) === id,
    );

    if (!found) {
      setLoading(false);
      return;
    }

    setMatch(found);

    sessionStorage.setItem("current_kundali_match", JSON.stringify(found));

    setLoading(false);
  }, [params, router]);

  /*
  |--------------------------------------------------------------------------
  | Loading
  |--------------------------------------------------------------------------
  */

  if (loading) {
    return (
      <>
        <Header />

        <main className="match-detail-loading">
          <div>Loading Kundli Match...</div>
        </main>

        <Footer />
      </>
    );
  }

  /*
  |--------------------------------------------------------------------------
  | Not Found
  |--------------------------------------------------------------------------
  */

  if (!match) {
    return (
      <>
        <Header />

        <main className="match-detail-page">
          <div className="match-detail-container">
            <div className="match-not-found">
              <div>
                <h1>Match Not Found</h1>

                <p>The requested Kundli match could not be found.</p>

                <button
                  type="button"
                  className="match-kundli-btn"
                  onClick={() => router.push("/kundli-matching")}
                >
                  ← Back to Kundli Matching
                </button>
              </div>
            </div>
          </div>
        </main>

        <Footer />
      </>
    );
  }

  /*
  |--------------------------------------------------------------------------
  | Parse Response
  |--------------------------------------------------------------------------
  */

  const response = getApiResponse(match);

  const report = getReport(response);

  const scoreInfo = getScore(report, match.match_type);

  const qualityLabel =
    scoreInfo.obtained !== null && scoreInfo.max
      ? getMatchQualityLabel(scoreInfo.obtained, scoreInfo.max)
      : "";

  const doshas = getDoshas(report);

  const conclusion = getConclusion(report);

  const ashtakootReport = getAshtakootReport((match as any)?.ashtakoot);

  const gunaRows = getGunaRows(ashtakootReport);

  const boyRashi = getPersonRashi(report, "boy");

  const girlRashi = getPersonRashi(report, "girl");

  const scorePercent =
    scoreInfo.obtained !== null && scoreInfo.max
      ? Math.min(100, (scoreInfo.obtained / scoreInfo.max) * 100)
      : 0;

  /*
  |--------------------------------------------------------------------------
  | UI
  |--------------------------------------------------------------------------
  */

  return (
    <>
      <Header />

      <main className="match-detail-page">
        <div className="match-detail-container">
          {/* <button
            type="button"
            className="match-detail-back"
            onClick={() => router.push("/kundli-matching")}
          >
            ← Back to Kundli Matching
          </button> */}

          {/* REPORT HEADER */}

          <div className="report-header">
            <h1>Kundli Matching Report</h1>

            <div className="report-people-row">
              <div className="report-people-line" />

              <div className="report-person">
                <div className="report-avatar-circle boy">
                  {match.boy.name.charAt(0).toUpperCase()}
                </div>

                <span>{match.boy.name}</span>
              </div>

              <div className="report-person compat">
                <div className="report-avatar-circle compat-circle">💗</div>

                <span>Compatibility</span>
              </div>

              <div className="report-person">
                <div className="report-avatar-circle girl">
                  {match.girl.name.charAt(0).toUpperCase()}
                </div>

                <span>{match.girl.name}</span>
              </div>
            </div>
          </div>

          {/* DETAIL CARDS */}

          <div className="report-detail-grid">
            <div className="report-detail-card">
              <div className="report-detail-header">
                <div className="report-avatar-circle small boy">
                  {match.boy.name.charAt(0).toUpperCase()}
                </div>

                <div>
                  <span className="report-detail-label">Your Details</span>

                  <strong>{match.boy.name}</strong>
                </div>
              </div>

              <div className="report-detail-body">
                <div>
                  <span>DOB:</span> {formatBirthDate(match.boy.birthDate)}
                </div>

                <div>
                  <span>Time:</span> {formatBirthTime(match.boy.birthTime)}
                </div>

                <div className="full">
                  <span>Place:</span> {match.boy.birthPlace}
                </div>

                {boyRashi && (
                  <div className="full">
                    <span>Janam Rashi:</span> {boyRashi}
                  </div>
                )}
              </div>
            </div>

            <div className="report-detail-card">
              <div className="report-detail-header">
                <div className="report-avatar-circle small girl">
                  {match.girl.name.charAt(0).toUpperCase()}
                </div>

                <div>
                  <span className="report-detail-label">Partner's Details</span>

                  <strong>{match.girl.name}</strong>
                </div>
              </div>

              <div className="report-detail-body">
                <div>
                  <span>DOB:</span> {formatBirthDate(match.girl.birthDate)}
                </div>

                <div>
                  <span>Time:</span> {formatBirthTime(match.girl.birthTime)}
                </div>

                <div className="full">
                  <span>Place:</span> {match.girl.birthPlace}
                </div>

                {girlRashi && (
                  <div className="full">
                    <span>Janam Rashi:</span> {girlRashi}
                  </div>
                )}
              </div>
            </div>
          </div>

          {/* SCORE RING */}

          <div className="report-score-card">
            <span className="report-score-title">Total Score</span>

            {scoreInfo.obtained !== null ? (
              <div
                className="score-ring"
                style={{ ["--pct" as any]: scorePercent }}
              >
                <div className="score-ring-inner">
                  <span className="score-ring-value">
                    {scoreInfo.obtained}
                    <small>/{scoreInfo.max || 36}</small>
                  </span>
                </div>
              </div>
            ) : (
              <div className="score-ring-placeholder">Report Ready</div>
            )}

            {(qualityLabel || scoreInfo.label) && (
              <span className="report-score-quality">
                {qualityLabel || scoreInfo.label}
              </span>
            )}

            {scoreInfo.secondaryRaw && (
              <span className="match-score-secondary">
                {scoreInfo.secondaryLabel} Score: {scoreInfo.secondaryRaw}
              </span>
            )}

            {conclusion && <p className="match-conclusion">{conclusion}</p>}
          </div>

          {/* GUNA MILAN TABLE */}

          {gunaRows.length > 0 && (
            <section className="match-section-card">
              <h2>Ashtakoot Guna Milan</h2>

              <div className="koota-table-wrap">
                <table className="koota-table guna-table">
                  <thead>
                    <tr>
                      <th>Guna</th>
                      <th>You</th>
                      <th>Partner</th>
                      <th>Points</th>
                      <th>Description</th>
                    </tr>
                  </thead>

                  <tbody>
                    {gunaRows.map((row) => {
                      const obtainedNum = Number(row.obtained);

                      const maxNum = Number(row.max);

                      const valid = !Number.isNaN(obtainedNum) && !Number.isNaN(maxNum) && maxNum > 0;

                      const nature = !valid
                        ? "bad"
                        : obtainedNum <= 0
                          ? "bad"
                          : obtainedNum >= maxNum
                            ? "good"
                            : "partial";

                      return (
                        <tr key={row.key}>
                          <td>
                            <strong>{row.label}</strong>{" "}
                            {row.subtitle && (
                              <span className="guna-subtitle">
                                ({row.subtitle})
                              </span>
                            )}
                          </td>

                          <td>{row.you}</td>

                          <td>{row.partner}</td>

                          <td>
                            <span className={`guna-points-badge ${nature}`}>
                              {row.obtained}/{row.max}
                            </span>
                          </td>

                          <td className="guna-description">
                            {row.description}
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            </section>
          )}

          {/* DOSHAS */}

          {doshas.map((item) => {
            /*
             * Color both person cards from the overall favorable/
             * unfavorable verdict (item.present, derived from the
             * detail text), not from each person's raw "has this
             * dosha" boolean — some doshas (e.g. Pitra) are only a
             * problem when just one partner has them; when both do,
             * it cancels out and the API's own detail text says so
             * ("this is good for marriage"), so the raw per-person
             * flag alone would show a misleading red/bad dot.
             */

            const boyBad = item.present;

            const girlBad = item.present;

            return (
              <section className="match-section-card" key={item.label}>
                <h2>{item.label}</h2>

                <div className="dosha-person-grid">
                  <div
                    className={`dosha-person-card ${
                      boyBad ? "has-dosha" : "no-dosha"
                    }`}
                  >
                    <div className="report-avatar-circle small boy">
                      {match.boy.name.charAt(0).toUpperCase()}
                    </div>

                    <div className="dosha-person-info">
                      <span className="report-detail-label">
                        Your Details
                      </span>

                      <strong>{match.boy.name}</strong>

                      {item.boyPoint !== null && (
                        <span className="dosha-person-value">
                          {formatPersonDoshaValue(item.boyPoint, item.label)}
                        </span>
                      )}
                    </div>

                    <span
                      className={`dosha-status-dot ${
                        boyBad ? "bad" : "good"
                      }`}
                    />
                  </div>

                  <div
                    className={`dosha-person-card ${
                      girlBad ? "has-dosha" : "no-dosha"
                    }`}
                  >
                    <div className="report-avatar-circle small girl">
                      {match.girl.name.charAt(0).toUpperCase()}
                    </div>

                    <div className="dosha-person-info">
                      <span className="report-detail-label">
                        Partner's Details
                      </span>

                      <strong>{match.girl.name}</strong>

                      {item.girlPoint !== null && (
                        <span className="dosha-person-value">
                          {formatPersonDoshaValue(item.girlPoint, item.label)}
                        </span>
                      )}
                    </div>

                    <span
                      className={`dosha-status-dot ${
                        girlBad ? "bad" : "good"
                      }`}
                    />
                  </div>
                </div>

                {item.detail && (
                  <p className="dosha-description">{item.detail}</p>
                )}
              </section>
            );
          })}

          {/* RAW REPORT FALLBACK */}

          {gunaRows.length === 0 &&
            doshas.length === 0 &&
            scoreInfo.obtained === null && (
              <section className="match-section-card">
                <h2>Match Report</h2>

                <pre className="match-raw-json">
                  {JSON.stringify(report, null, 2)}
                </pre>
              </section>
            )}
        </div>
      </main>

      <Footer />
    </>
  );
}

/*
|--------------------------------------------------------------------------
| Get API Response
|--------------------------------------------------------------------------
*/

function getApiResponse(match: SavedMatch): AnyObject {
  const raw = (match as any)?.response;

  if (raw && typeof raw === "object") {
    return raw;
  }

  return {};
}

/*
|--------------------------------------------------------------------------
| Get Report (unwraps common wrapper keys)
|--------------------------------------------------------------------------
*/

function getReport(response: AnyObject): AnyObject {
  /*
   * The backend wraps the actual report in one or more
   * "data" envelopes, e.g. { data: { charged, data: {...} } }.
   * Keep unwrapping "data" until we land on an object that
   * actually looks like a match report.
   */

  let current: AnyObject = response || {};

  let guard = 0;

  while (
    current &&
    typeof current === "object" &&
    !isReportShape(current) &&
    current.data &&
    typeof current.data === "object" &&
    !Array.isArray(current.data) &&
    guard < 5
  ) {
    current = current.data;
    guard++;
  }

  if (Array.isArray(response?.recordList)) {
    return response.recordList[0] || {};
  }

  return current || {};
}

function isReportShape(value: AnyObject): boolean {
  return (
    "ashtakoot_score" in value ||
    "dashkoot_score" in value ||
    Object.keys(value).some((key) => /dosh$/i.test(key))
  );
}

/*
|--------------------------------------------------------------------------
| Get Ashtakoot (per-guna) Report
|--------------------------------------------------------------------------
*/

function getAshtakootReport(raw: any): AnyObject {
  if (!raw || typeof raw !== "object") {
    return {};
  }

  const allAliases = GUNA_DEFS.flatMap((def) => def.aliases);

  const looksLikeGuna = (obj: AnyObject) =>
    obj && typeof obj === "object" && allAliases.some((alias) => alias in obj);

  let current: AnyObject = raw;

  let guard = 0;

  while (
    current &&
    typeof current === "object" &&
    !Array.isArray(current) &&
    !looksLikeGuna(current) &&
    current.data &&
    typeof current.data === "object" &&
    !Array.isArray(current.data) &&
    guard < 5
  ) {
    current = current.data;
    guard++;
  }

  return current || {};
}

/*
|--------------------------------------------------------------------------
| Get Guna Milan Rows
|--------------------------------------------------------------------------
*/

function getGunaRows(report: AnyObject) {
  const rows: {
    key: string;
    label: string;
    subtitle: string;
    you: string;
    partner: string;
    obtained: number | string;
    max: number | string;
    description: string;
  }[] = [];

  for (const def of GUNA_DEFS) {
    let value: any;

    let matchedAlias: string | undefined;

    for (const alias of def.aliases) {
      if (report?.[alias] !== undefined && report?.[alias] !== null) {
        value = report[alias];
        matchedAlias = alias;
        break;
      }
    }

    if (value === undefined || value === null) {
      continue;
    }

    let you = "-";

    let partner = "-";

    let obtained: number | string = "-";

    let max: number | string = def.max;

    let description = def.defaultDescription;

    if (typeof value === "object" && !Array.isArray(value)) {
      // Real shape names the per-person fields "boy_<suffix>"/
      // "girl_<suffix>" — try each known suffix (plus the matched
      // top-level key itself) before the generic you/boy/male aliases.
      const suffixes = [...def.personSuffixes, matchedAlias].filter(Boolean) as string[];

      for (const suffix of suffixes) {
        const boyValue = value[`boy_${suffix}`];

        if (you === "-" && boyValue !== undefined && boyValue !== null) {
          you = String(boyValue);
        }

        const girlValue = value[`girl_${suffix}`];

        if (partner === "-" && girlValue !== undefined && girlValue !== null) {
          partner = String(girlValue);
        }
      }

      you = you !== "-" ? you : (value.you ?? value.boy ?? value.male ?? value.person1 ?? you);

      partner =
        partner !== "-" ? partner : (value.partner ?? value.girl ?? value.female ?? value.person2 ?? partner);

      // Real shape scores each guna under a field with the SAME name
      // as the guna itself (report.tara.tara), and the max under
      // "full_score" — try those first, then the generic aliases.
      const selfScore = matchedAlias ? value[matchedAlias] : undefined;

      const parsedScore =
        (typeof selfScore === "number" ? { obtained: selfScore, max: firstNumber([value.full_score]) ?? def.max } : null) ??
        parseScoreString(value.points ?? value.score) ??
        (() => {
          const obtainedValue = firstNumber([value.obtained, value.points, value.score]);

          if (obtainedValue === null) {
            return null;
          }

          return {
            obtained: obtainedValue,
            max: firstNumber([value.full_score, value.max, value.max_points]) ?? def.max,
          };
        })();

      if (parsedScore) {
        obtained = parsedScore.obtained;
        max = parsedScore.max;
      }

      description = value.description || value.desc || value.remark || description;
    } else {
      const parsed = parseScoreString(value);

      if (parsed) {
        obtained = parsed.obtained;
        max = parsed.max;
      } else if (typeof value === "number") {
        obtained = value;
      }
    }

    rows.push({
      key: def.key,
      label: def.label,
      subtitle: def.subtitle,
      you,
      partner,
      obtained,
      max,
      description,
    });
  }

  /*
   * Fallback: some APIs return an array of guna objects
   * instead of fixed keys.
   */

  const list =
    Array.isArray(report?.guna_milan) ? report.guna_milan :
    Array.isArray(report?.kootas) ? report.kootas :
    null;

  if (rows.length === 0 && list) {
    for (const item of list) {
      const label = item?.name || item?.key || item?.title;

      if (!label) {
        continue;
      }

      rows.push({
        key: String(label).toLowerCase(),
        label,
        subtitle: item?.subtitle || "",
        you: item?.you ?? item?.boy ?? "-",
        partner: item?.partner ?? item?.girl ?? "-",
        obtained: firstNumber([item?.obtained, item?.points]) ?? "-",
        max: firstNumber([item?.max]) ?? "-",
        description: item?.description || "",
      });
    }
  }

  return rows;
}

/*
|--------------------------------------------------------------------------
| Get Person Rashi (Janam Rashi)
|--------------------------------------------------------------------------
|
| Not confirmed against a real response yet — the aggregate/match
| report presumably computes each person's moon sign somewhere since
| it needs it for the Guna Milan calculation, but the exact field name
| is unknown. Scans a wide set of plausible flat and nested key names
| and simply omits the row if none match, rather than guessing wrong.
*/

function getPersonRashi(report: AnyObject, side: "boy" | "girl"): string {
  const prefixes = side === "boy"
    ? ["boy", "male", "person1", "groom"]
    : ["girl", "female", "person2", "bride"];

  const suffixes = ["rashi", "janam_rashi", "moon_sign", "moonsign", "rasi", "zodiac"];

  for (const prefix of prefixes) {
    for (const suffix of suffixes) {
      const value = report?.[`${prefix}_${suffix}`];

      if (typeof value === "string" && value.trim()) {
        return value.trim();
      }
    }

    const nested = report?.[`${prefix}_details`] ?? report?.[prefix];

    if (nested && typeof nested === "object") {
      const value =
        nested.rashi ??
        nested.janam_rashi ??
        nested.moon_sign ??
        nested.moonsign ??
        nested.zodiac ??
        nested.rasi?.name ??
        nested.rasi;

      if (typeof value === "string" && value.trim()) {
        return value.trim();
      }
    }
  }

  return "";
}

/*
|--------------------------------------------------------------------------
| Get Score
|--------------------------------------------------------------------------
*/

function getScore(report: AnyObject, matchType: string) {
  /*
   * The aggregate endpoint returns both totals as "27/36" style
   * strings ("ashtakoot_score", "dashkoot_score") regardless of
   * the requested chart style — show the one the user asked for
   * as the headline score, the other as a secondary chip.
   */

  const useSouth = matchType === "south";

  const primaryRaw = useSouth
    ? report?.dashkoot_score ?? report?.ashtakoot_score
    : report?.ashtakoot_score ?? report?.dashkoot_score;

  const secondaryRaw = useSouth ? report?.ashtakoot_score : report?.dashkoot_score;

  const primary =
    parseScoreString(primaryRaw) ??
    (() => {
      const obtained = firstNumber([
        report?.total_points,
        report?.obtained_points,
        report?.total_score,
        report?.score,
        report?.points,
      ]);

      const max = firstNumber([report?.max_points, report?.total_max_points, report?.out_of]);

      return obtained !== null ? { obtained, max: max ?? 36 } : null;
    })();

  return {
    obtained: primary?.obtained ?? null,
    max: primary?.max ?? null,
    label: useSouth ? "Dashakoot (South Indian) Match" : "Ashtakoot (North Indian) Match",
    secondaryRaw: secondaryRaw ?? null,
    secondaryLabel: useSouth ? "Ashtakoot" : "Dashakoot",
  };
}

function getMatchQualityLabel(obtained: number, max: number): string {
  if (!max) {
    return "";
  }

  const scaledToThirtySix = (obtained / max) * 36;

  if (scaledToThirtySix >= 32) {
    return "Excellent Match";
  }

  if (scaledToThirtySix >= 24) {
    return "Good Match";
  }

  if (scaledToThirtySix >= 18) {
    return "Average Match";
  }

  return "Not Recommended";
}

function parseScoreString(value: any): { obtained: number; max: number } | null {
  if (typeof value === "number" && !Number.isNaN(value)) {
    return { obtained: value, max: 36 };
  }

  if (typeof value !== "string") {
    return null;
  }

  const parts = value.split("/");

  if (parts.length !== 2) {
    return null;
  }

  const obtained = Number(parts[0].trim());
  const max = Number(parts[1].trim());

  if (Number.isNaN(obtained) || Number.isNaN(max)) {
    return null;
  }

  return { obtained, max };
}

function firstNumber(values: any[]): number | null {
  for (const value of values) {
    if (typeof value === "number" && !Number.isNaN(value)) {
      return value;
    }

    if (typeof value === "string" && value.trim() !== "" && !Number.isNaN(Number(value))) {
      return Number(value);
    }
  }

  return null;
}

/*
|--------------------------------------------------------------------------
| Get Doshas
|--------------------------------------------------------------------------
*/

function getDoshas(report: AnyObject) {
  /*
   * The backend names every dosha field with a "...dosh" suffix
   * (rajjudosh, vedhadosh, mangaldosh, pitradosh, kaalsarpdosh, ...)
   * and an optional sibling "..._points" object with per-person
   * detail. Scan for that pattern instead of hardcoding names, so
   * any dosha the API adds later shows up automatically.
   */

  const items: {
    label: string;
    present: boolean;
    detail: string;
    boyPoint: any;
    girlPoint: any;
  }[] = [];

  const doshaKeys = Object.keys(report || {}).filter(
    (key) => /dosh$/i.test(key) && !/_points$/i.test(key),
  );

  for (const key of doshaKeys) {
    /*
     * Points key naming is inconsistent upstream — most doshas
     * keep the "dosh" suffix (mangaldosh_points), but at least
     * one drops it (kaalsarpdosh -> kaalsarp_points). Try both.
     */

    const points =
      report[`${key}_points`] ??
      report[`${key.replace(/dosh$/i, "")}_points`];

    items.push(buildDosha(key, report[key], points));
  }

  return items;
}

function buildDosha(key: string, value: any, points: any) {
  const label = formatDoshaLabel(key);

  let present: boolean;

  let detail: string;

  if (typeof value === "boolean") {
    present = value;

    detail = value ? "Present" : "Not present";
  } else if (typeof value === "object" && value !== null) {
    present = Boolean(value?.present ?? value?.is_present ?? value?.dosha);

    detail =
      value?.description || value?.remark || value?.detail || (present ? "Present" : "Not present");
  } else {
    const text = String(value ?? "");

    detail = text;

    present = /not\s+(favorable|good|auspicious)|unfavorable|inauspicious/i.test(text)
      ? true
      : !/favorable|auspicious|good for marriage|does not have|no dosha|absent/i.test(text);
  }

  let boyPoint: any = null;

  let girlPoint: any = null;

  if (points && typeof points === "object") {
    boyPoint = "boy" in points ? points.boy : null;
    girlPoint = "girl" in points ? points.girl : null;
  }

  return { label, present, detail, boyPoint, girlPoint };
}

function formatPersonDoshaValue(value: any, label: string): string {
  if (typeof value === "boolean") {
    return value ? `Has ${label}` : `No ${label}`;
  }

  return `Score: ${value}`;
}

function formatDoshaLabel(key: string): string {
  let base = /dosh$/i.test(key) ? key.replace(/dosh$/i, "") : key;

  base = base.charAt(0).toUpperCase() + base.slice(1);

  return `${base} Dosha`;
}

/*
|--------------------------------------------------------------------------
| Get Conclusion
|--------------------------------------------------------------------------
*/

function getConclusion(report: AnyObject): string {
  const value =
    report?.conclusion ||
    report?.summary ||
    report?.remark ||
    report?.bot_response ||
    report?.description ||
    report?.compatibility_message;

  return typeof value === "string" ? value : "";
}

/*
|--------------------------------------------------------------------------
| Date / Time formatters
|--------------------------------------------------------------------------
*/

function formatBirthDate(date: string): string {
  if (!date) {
    return "";
  }

  const parts = date.split("-");

  if (parts.length !== 3) {
    return date;
  }

  const months = [
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  ];

  return `${parts[2]} ${months[Number(parts[1]) - 1] || ""} ${parts[0]}`;
}

function formatBirthTime(time: string): string {
  if (!time) {
    return "";
  }

  const [hours, minutes] = time.split(":");

  let hour = Number(hours);

  const ampm = hour >= 12 ? "PM" : "AM";

  hour = hour % 12 || 12;

  return `${String(hour).padStart(2, "0")}:${minutes} ${ampm}`;
}
