"use client";

import { useCallback, useMemo, useState } from "react";
import { useAsyncEffect } from "@/hooks/use-async-effect";
import { useTranslationRef } from "@/hooks/use-translation-ref";
import { format, subDays } from "date-fns";
import { useTranslation } from "react-i18next";

import { getAdminDashboardAnalytics } from "@/api/admin-dashboard";
import { useAdminPlayCodeLabel } from "@/hooks/use-admin-play-type-catalog";
import { getAdminRequestLocale } from "@/lib/admin-locale";
import {
  coerceAdminMinor,
  formatAdminCreditMajor,
  formatAdminMinorUnits,
  getAdminCurrencyDecimalPlaces,
} from "@/lib/money";
import { LotteryApiBizError } from "@/types/api/errors";
import type {
  AdminDashboardAnalyticsData,
  AdminDashboardAnalyticsAgentRow,
  DashboardAnalyticsMetric,
  DashboardAnalyticsPeriod,
} from "@/types/api/admin-dashboard-analytics";

export const DASHBOARD_ANALYTICS_PERIODS: DashboardAnalyticsPeriod[] = [
  "today",
  "last_7_days",
  "last_30_days",
  "this_month",
  "lifetime",
  "custom",
];

export const DASHBOARD_RANKING_METRICS: DashboardAnalyticsMetric[] = ["bet", "payout", "profit"];

/** 代理/玩家授信类字段：主货币整数 → 带小数展示（勿用 {@link formatDashboardMoneyMinor}）。 */
export function formatDashboardCreditMajor(major: number, currencyCode: string | null): string {
  const code = (currencyCode ?? "NPR").toUpperCase();
  const safeMajor = Number.isFinite(major) ? major : 0;
  const decimals = getAdminCurrencyDecimalPlaces(code);
  try {
    return new Intl.NumberFormat(getAdminRequestLocale(), {
      style: "currency",
      currency: code,
      minimumFractionDigits: decimals,
      maximumFractionDigits: decimals,
    }).format(safeMajor);
  } catch {
    return formatAdminCreditMajor(safeMajor, code, decimals);
  }
}

export function formatDashboardMoneyMinor(minor: number, currencyCode: string | null): string {
  const safeMinor = coerceAdminMinor(minor);
  const code = (currencyCode ?? "NPR").toUpperCase();
  const decimals = getAdminCurrencyDecimalPlaces(code);
  const major = safeMinor / 10 ** decimals;
  try {
    return new Intl.NumberFormat(getAdminRequestLocale(), {
      style: "currency",
      currency: code,
      minimumFractionDigits: decimals,
      maximumFractionDigits: decimals,
    }).format(major);
  } catch {
    return formatAdminMinorUnits(safeMinor, code, decimals);
  }
}

export function formatDashboardSignedMoneyMinor(minor: number, currencyCode: string | null): string {
  if (minor === 0) {
    return formatDashboardMoneyMinor(0, currencyCode);
  }
  const s = minor > 0 ? "+" : "−";
  return `${s}${formatDashboardMoneyMinor(Math.abs(minor), currencyCode)}`;
}

export function useDashboardAnalytics({
  enabled,
  playOptions,
  scope,
}: {
  enabled: boolean;
  playOptions: { code: string; label: string }[];
  scope: { siteCode: string; agentNodeId: number | undefined };
}) {
  const { t } = useTranslation(["dashboard", "common"]);
  const tRef = useTranslationRef(["dashboard", "common"]);
  const playLabel = useAdminPlayCodeLabel();

  const [period, setPeriod] = useState<DashboardAnalyticsPeriod>("last_7_days");
  const [rankingMetric, setRankingMetric] = useState<DashboardAnalyticsMetric>("bet");
  const [playCode, setPlayCode] = useState<string>("");
  const [customFrom, setCustomFrom] = useState(() => format(subDays(new Date(), 6), "yyyy-MM-dd"));
  const [customTo, setCustomTo] = useState(() => format(new Date(), "yyyy-MM-dd"));

  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [data, setData] = useState<AdminDashboardAnalyticsData | null>(null);

  const load = useCallback(async () => {
    if (!enabled) {
      setLoading(false);
      setData(null);
      return;
    }

    setLoading(true);
    setError(null);

    try {
      const payload = await getAdminDashboardAnalytics({
        period,
        metric: "overview",
        play_code: playCode !== "" ? playCode : undefined,
        site_code: scope.siteCode || undefined,
        agent_node_id: scope.agentNodeId,
        ...(period === "custom" ? { date_from: customFrom, date_to: customTo } : {}),
      });
      setData(payload);
    } catch (e) {
      setData(null);
      const raw = e instanceof LotteryApiBizError ? e.message : "";
      const needsAuthSync =
        raw.includes("admin.dashboard.analytics") || raw.includes("资源未配置");
      setError(
        needsAuthSync
          ? tRef.current("warnings.apiResourceMissing")
          : raw || tRef.current("warnings.loadFailed"),
      );
    } finally {
      setLoading(false);
    }
  }, [enabled, period, playCode, customFrom, customTo, scope.agentNodeId, scope.siteCode, tRef]);

  useAsyncEffect(() => {
    void load();
  }, [enabled, period, playCode, customFrom, customTo, scope.agentNodeId, scope.siteCode]);

  const currency = data?.currency_code ?? null;
  const summary = data?.summary;
  const profitScope = data?.profit_scope ?? "house_gross";

  const periodRangeLabel = useMemo(() => {
    if (!data) {
      return null;
    }
    return data.date_from === data.date_to
      ? data.date_from
      : `${data.date_from} — ${data.date_to}`;
  }, [data]);

  const playFilterLabel = useMemo(() => {
    if (playCode === "") {
      return t("analytics.allPlays");
    }
    return playOptions.find((p) => p.code === playCode)?.label ?? playCode;
  }, [playCode, playOptions, t]);

  const resolvePlayLabel = useCallback(
    (code: string, dimension: number) => {
      const base = playLabel(code);
      return dimension > 0 ? `${base} · ${dimension}D` : base;
    },
    [playLabel],
  );

  const topPlayRows = useMemo(() => {
    if (!data) {
      return [];
    }
    const rows = [...data.play_breakdown];
    rows.sort((a, b) => {
      if (rankingMetric === "payout") {
        return b.total_payout_minor - a.total_payout_minor;
      }
      if (rankingMetric === "profit") {
        return b.approx_house_gross_minor - a.approx_house_gross_minor;
      }
      return b.total_bet_minor - a.total_bet_minor;
    });
    return rows.slice(0, 5);
  }, [data, rankingMetric]);

  const metricAgentValue = useCallback(
    (row: AdminDashboardAnalyticsAgentRow): number => {
      if (rankingMetric === "payout") {
        return row.total_payout_minor;
      }
      if (rankingMetric === "profit") {
        return row.approx_house_gross_minor;
      }
      return row.total_bet_minor;
    },
    [rankingMetric],
  );

  const topAgentRows = useMemo(() => {
    if (!data) {
      return [];
    }
    const rows = [...data.agent_breakdown];
    rows.sort((a, b) => metricAgentValue(b) - metricAgentValue(a));
    return rows.slice(0, 5);
  }, [data, metricAgentValue]);

  const sparklines = useMemo(() => {
    const series = data?.daily_series ?? [];
    return {
      bet: series.map((d) => d.total_bet_minor),
      payout: series.map((d) => d.total_payout_minor),
      profit: series.map((d) => d.approx_house_gross_minor),
    };
  }, [data?.daily_series]);

  return {
    enabled,
    period,
    setPeriod,
    rankingMetric,
    setRankingMetric,
    playCode,
    setPlayCode,
    customFrom,
    setCustomFrom,
    customTo,
    setCustomTo,
    loading,
    error,
    data,
    currency,
    summary,
    profitScope,
    periodRangeLabel,
    playFilterLabel,
    playOptions,
    resolvePlayLabel,
    topPlayRows,
    topAgentRows,
    sparklines,
    formatMoney: formatDashboardMoneyMinor,
    formatSignedMoney: formatDashboardSignedMoneyMinor,
    t,
  };
}

export type DashboardAnalyticsState = ReturnType<typeof useDashboardAnalytics>;
