import {
  Bar,
  BarChart,
  CartesianGrid,
  Legend,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
} from "recharts"

import type { ChartReportResponse, ChartReportSeries, CurrencyTotal, ReportChartBucket } from "../../api/reports"
import { useTranslation } from "../../hooks/useTranslation"

const PERSIAN_DIGITS = "۰۱۲۳۴۵۶۷۸۹"
const SERIES_PALETTE = ["#0ea5e9", "#f97316", "#10b981", "#8b5cf6", "#ef4444", "#eab308", "#14b8a6", "#3b82f6"]

type ChartRow = {
  bucket_key: string
  bucket_label: string
  tooltip_label: string
  [key: string]: string | number
}

const localizeDigits = (value: string, lang: "en" | "fa") =>
  lang === "fa" ? value.replace(/\d/g, (digit) => PERSIAN_DIGITS[Number(digit)] || digit) : value

const shouldTrimCurrencyDecimals = (currency?: string | null) => {
  const normalized = (currency || "").toUpperCase()
  return normalized === "IRR" || normalized === "IRT"
}

const formatAmount = (value: string, lang: "en" | "fa", currency?: string | null) => {
  const numeric = Number(value.replace(/,/g, ""))
  if (Number.isNaN(numeric)) {
    return localizeDigits(value, lang)
  }

  const [integerPart, fractionalPart] = value.replace(/,/g, "").split(".")
  const grouped = Math.abs(Number(integerPart)).toLocaleString("en-US")
  const signed = value.startsWith("-") ? `-${grouped}` : grouped
  const normalizedFraction =
    fractionalPart && !shouldTrimCurrencyDecimals(currency) ? fractionalPart.replace(/0+$/, "") : ""
  const formatted = normalizedFraction ? `${signed}.${normalizedFraction}` : signed
  return localizeDigits(formatted, lang)
}

const currencyLabel = (currency: string, lang: "en" | "fa") => {
  if (lang !== "fa") {
    return currency.toUpperCase()
  }

  return (
    {
      USD: "دلار",
      EUR: "یورو",
      GBP: "پوند",
      IRR: "ریال",
      IRT: "تومان",
      AED: "درهم",
      TRY: "لیر",
    }[currency.toUpperCase()] || currency.toUpperCase()
  )
}

const formatMoneyTotals = (totals: CurrencyTotal[], lang: "en" | "fa") => {
  if (!totals.length) {
    return "-"
  }

  return totals.map((item) => `${formatAmount(item.amount, lang, item.currency)} ${currencyLabel(item.currency, lang)}`).join(" | ")
}

const formatSecondsTick = (value: number, lang: "en" | "fa") => {
  const hours = value / 3600
  const rounded = hours >= 10 ? hours.toFixed(0) : hours.toFixed(1)
  return localizeDigits(rounded, lang)
}

const parseIsoDate = (value: string) => {
  const [year, month, day] = value.split("-").map(Number)
  return new Date(year, (month || 1) - 1, day || 1)
}

const formatIsoDate = (value: Date) => {
  const year = value.getFullYear()
  const month = String(value.getMonth() + 1).padStart(2, "0")
  const day = String(value.getDate()).padStart(2, "0")
  return `${year}-${month}-${day}`
}

const monthKeyFromDate = (value: Date) => `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, "0")}`

const getCalendarLocale = (lang: "en" | "fa") => (lang === "fa" ? "fa-IR-u-ca-persian" : "en-US")

const getDailyAxisLabel = (date: Date, lang: "en" | "fa", period: string) => {
  if (period === "this_week") {
    return new Intl.DateTimeFormat(getCalendarLocale(lang), { weekday: "short" }).format(date)
  }

  return new Intl.DateTimeFormat(getCalendarLocale(lang), { day: "numeric" }).format(date)
}

const getDailyTooltipLabel = (date: Date, lang: "en" | "fa") =>
  new Intl.DateTimeFormat(getCalendarLocale(lang), {
    weekday: "long",
    month: "long",
    day: "numeric",
  }).format(date)

const getMonthlyAxisLabel = (bucketKey: string, lang: "en" | "fa") => {
  const [year, month] = bucketKey.split("-").map(Number)
  return new Intl.DateTimeFormat(getCalendarLocale(lang), { month: "short" }).format(
    new Date(year, (month || 1) - 1, 1),
  )
}

const getMonthlyTooltipLabel = (bucketKey: string, lang: "en" | "fa") => {
  const [year, month] = bucketKey.split("-").map(Number)
  return new Intl.DateTimeFormat(getCalendarLocale(lang), { month: "long", year: "numeric" }).format(
    new Date(year, (month || 1) - 1, 1),
  )
}

const buildDailyBuckets = (
  fromDate: string,
  toDate: string,
  existing: ReportChartBucket[],
  lang: "en" | "fa",
  period: string,
) => {
  const map = new Map(existing.map((bucket) => [bucket.bucket_key, bucket]))
  const result: ReportChartBucket[] = []
  const cursor = parseIsoDate(fromDate)
  const limit = parseIsoDate(toDate)

  while (cursor.getTime() <= limit.getTime()) {
    const key = formatIsoDate(cursor)
    const existingBucket = map.get(key)
    result.push(
      existingBucket ?? {
        bucket_key: key,
        bucket_label: getDailyAxisLabel(cursor, lang, period),
        total_seconds: 0,
        total_duration: "00:00:00",
      },
    )
    cursor.setDate(cursor.getDate() + 1)
  }

  return result.map((bucket) => ({
    ...bucket,
    bucket_label: getDailyAxisLabel(parseIsoDate(bucket.bucket_key), lang, period),
  }))
}

const buildMonthlyBuckets = (fromDate: string, toDate: string, existing: ReportChartBucket[], lang: "en" | "fa") => {
  const map = new Map(existing.map((bucket) => [bucket.bucket_key, bucket]))
  const result: ReportChartBucket[] = []
  const start = parseIsoDate(fromDate)
  const end = parseIsoDate(toDate)
  const cursor = new Date(start.getFullYear(), start.getMonth(), 1)
  const limit = new Date(end.getFullYear(), end.getMonth(), 1)

  while (cursor.getTime() <= limit.getTime()) {
    const key = monthKeyFromDate(cursor)
    const existingBucket = map.get(key)
    result.push(
      existingBucket ?? {
        bucket_key: key,
        bucket_label: getMonthlyAxisLabel(key, lang),
        total_seconds: 0,
        total_duration: "00:00:00",
      },
    )
    cursor.setMonth(cursor.getMonth() + 1)
  }

  return result.map((bucket) => ({
    ...bucket,
    bucket_label: getMonthlyAxisLabel(bucket.bucket_key, lang),
  }))
}

const buildSeriesBuckets = (
  series: ChartReportSeries,
  data: ChartReportResponse,
  lang: "en" | "fa",
  useMonthlyBuckets: boolean,
) =>
  useMonthlyBuckets
    ? buildMonthlyBuckets(data.scope.from_date, data.scope.to_date, series.buckets, lang)
    : buildDailyBuckets(data.scope.from_date, data.scope.to_date, series.buckets, lang, data.scope.period)

const createSeriesKey = (series: ChartReportSeries, index: number) => series.user?.id ?? `series_${index}`

const buildChartRows = (data: ChartReportResponse, lang: "en" | "fa") => {
  const useMonthlyBuckets =
    data.scope.period === "this_year" ||
    data.scope.period === "half_year_first" ||
    data.scope.period === "half_year_second"

  const normalizedSeries = data.series.map((series) => buildSeriesBuckets(series, data, lang, useMonthlyBuckets))
  const baseBuckets = normalizedSeries[0] ?? []

  const rows: ChartRow[] = baseBuckets.map((bucket, bucketIndex) => {
    const tooltipLabel = useMonthlyBuckets
      ? getMonthlyTooltipLabel(bucket.bucket_key, lang)
      : getDailyTooltipLabel(parseIsoDate(bucket.bucket_key), lang)

    const row: ChartRow = {
      bucket_key: bucket.bucket_key,
      bucket_label: bucket.bucket_label,
      tooltip_label: tooltipLabel,
    }

    data.series.forEach((series, seriesIndex) => {
      const seriesKey = createSeriesKey(series, seriesIndex)
      row[seriesKey] = normalizedSeries[seriesIndex]?.[bucketIndex]?.total_seconds ?? 0
    })

    return row
  })

  return { rows, useMonthlyBuckets }
}

function ChartTooltip({
  active,
  payload,
  label,
  lang,
  totalHoursLabel,
}: {
  active?: boolean
  payload?: ReadonlyArray<{ color?: string; dataKey?: string | number | ((obj: unknown) => unknown); name?: string | number; value?: unknown }>
  label: string
  lang: "en" | "fa"
  totalHoursLabel: string
}) {
  if (!active || !payload?.length) {
    return null
  }

  return (
    <div className="rounded-2xl border border-slate-200 bg-white/95 px-3 py-2 shadow-xl shadow-slate-200/60 backdrop-blur dark:border-slate-700 dark:bg-slate-900/95 dark:shadow-black/30">
      <div className="text-xs font-semibold text-slate-500 dark:text-slate-400">{label}</div>
      <div className="mt-2 space-y-1">
        {payload.map((item) => {
          const seconds = Number(item.value || 0)
          const hours = seconds / 3600
          return (
            <div key={String(item.dataKey)} className="flex items-center gap-2 text-sm text-slate-900 dark:text-white">
              <span className="h-2.5 w-2.5 rounded-full" style={{ backgroundColor: item.color }} />
              <span className="font-medium">{item.name}</span>
              <span className="text-slate-500 dark:text-slate-400">
                {totalHoursLabel}: {localizeDigits(hours.toFixed(hours >= 10 ? 0 : 1), lang)}
              </span>
            </div>
          )
        })}
      </div>
    </div>
  )
}

export function ReportsChartPanel({
  data,
  labels,
  isLoading,
}: {
  data: ChartReportResponse | null
  labels: Record<string, string>
  isLoading: boolean
}) {
  const { lang } = useTranslation()

  if (isLoading) {
    return (
      <div className="space-y-4">
        <div className="grid grid-cols-2 gap-3 xl:grid-cols-4">
          {Array.from({ length: 4 }).map((_, index) => (
            <div key={index} className="rounded-3xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900">
              <div className="mb-3 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500 dark:text-slate-400">
                {labels.loading}
              </div>
              <div className="h-8 animate-pulse rounded-xl bg-slate-200/80 dark:bg-slate-800/80" />
            </div>
          ))}
        </div>

        <div className="rounded-3xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900 sm:p-5">
          <div className="mb-4 flex items-center justify-between gap-3">
            <div className="text-sm font-semibold text-slate-900 dark:text-white">{labels.chart}</div>
            <div className="text-xs text-slate-500 dark:text-slate-400">{labels.loading}</div>
          </div>
          <div className="h-[320px] animate-pulse rounded-2xl bg-slate-200/80 dark:bg-slate-800/80 sm:h-[360px]" />
        </div>
      </div>
    )
  }

  if (!data || data.series.length === 0) {
    return null
  }

  const { rows, useMonthlyBuckets } = buildChartRows(data, lang)
  const interval = useMonthlyBuckets ? 0 : rows.length > 20 ? Math.ceil(rows.length / 10) - 1 : 0
  const chartMinWidth = Math.max(640, rows.length * (useMonthlyBuckets ? 110 : 52))
  const isMultiSeries = data.series.length > 1
  return (
    <div className="space-y-4">
      <div className="grid grid-cols-2 gap-3 xl:grid-cols-4">
        <div className="rounded-3xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900">
          <div className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500 dark:text-slate-400">{labels.totalHours}</div>
          <div className="mt-2 text-xl font-bold text-slate-900 dark:text-white sm:text-2xl">
            {localizeDigits(data.summary.total_duration, lang)}
          </div>
        </div>
        <div className="rounded-3xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900">
          <div className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500 dark:text-slate-400">{labels.billableHours}</div>
          <div className="mt-2 text-xl font-bold text-slate-900 dark:text-white sm:text-2xl">
            {localizeDigits(data.summary.billable_duration, lang)}
          </div>
        </div>
        <div className="rounded-3xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900">
          <div className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500 dark:text-slate-400">{labels.nonBillableHours}</div>
          <div className="mt-2 text-xl font-bold text-slate-900 dark:text-white sm:text-2xl">
            {localizeDigits(data.summary.non_billable_duration, lang)}
          </div>
        </div>
        <div className="rounded-3xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900">
          <div className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500 dark:text-slate-400">{labels.totalIncome}</div>
          <div className="mt-2 text-sm font-semibold leading-6 text-slate-900 dark:text-white sm:text-base">
            {formatMoneyTotals(data.summary.income_totals, lang)}
          </div>
        </div>
      </div>

      <div className="rounded-3xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900 sm:p-5">
        <div className="mb-4 flex items-center justify-between gap-3">
          <div className="text-sm font-semibold text-slate-900 dark:text-white">{labels.chart}</div>
          <div className="text-xs text-slate-500 dark:text-slate-400">{localizeDigits(`${rows.length}`, lang)}</div>
        </div>

        <div className="overflow-x-auto pb-2">
          <div className="h-[300px] min-w-full sm:h-[360px]" style={{ minWidth: `${chartMinWidth}px` }}>
            <ResponsiveContainer width="100%" height="100%">
              <BarChart data={rows} barCategoryGap={useMonthlyBuckets ? "26%" : "18%"} margin={{ top: 8, right: 18, bottom: 16, left: 10 }}>
                <CartesianGrid strokeDasharray="4 6" stroke="currentColor" className="text-slate-200 dark:text-slate-800" vertical={false} />
                <XAxis
                  dataKey="bucket_label"
                  interval={interval}
                  tickLine={false}
                  axisLine={false}
                  height={48}
                  tickMargin={10}
                  tick={{ fontSize: 11, fill: "#64748b" }}
                />
                <YAxis
                  tickFormatter={(value) => formatSecondsTick(value, lang)}
                  tickLine={false}
                  axisLine={false}
                  width={54}
                  tickMargin={10}
                  tick={{ fontSize: 11, fill: "#64748b" }}
                />
                <Tooltip
                  cursor={{ fill: "rgba(14,165,233,0.08)" }}
                  content={({ active, payload, label }) => (
                    <ChartTooltip
                      active={active}
                      payload={payload}
                      label={typeof label === "string" ? label : rows[0]?.tooltip_label || ""}
                      lang={lang}
                      totalHoursLabel={labels.totalHours}
                    />
                  )}
                  labelFormatter={(_, payload) => String(payload?.[0]?.payload?.tooltip_label || "")}
                />
                {isMultiSeries ? (
                  <Legend
                    verticalAlign="top"
                    align="left"
                    wrapperStyle={{ paddingBottom: "16px", fontSize: "12px" }}
                  />
                ) : null}
                {data.series.map((series, index) => {
                  const dataKey = createSeriesKey(series, index)
                  return (
                    <Bar
                      key={dataKey}
                      dataKey={dataKey}
                      name={series.user?.name || labels.totalHours}
                      fill={SERIES_PALETTE[index % SERIES_PALETTE.length]}
                      radius={[12, 12, 4, 4]}
                      maxBarSize={useMonthlyBuckets ? 36 : 22}
                    />
                  )
                })}
              </BarChart>
            </ResponsiveContainer>
          </div>
        </div>
      </div>
    </div>
  )
}
