import { useState, useMemo } from "react"
import { Navigate } from "react-router-dom"
import { useTranslation } from "react-i18next"
import { useFirstRunState } from "@/hooks/useFirstRunState"
import { useBudgets, useBudgetDetail } from "@/hooks/useBudgets"
import { useMonthParam } from "@/hooks/useMonthParam"
import type { CategoryType } from "@/lib/types"
import { formatCurrency } from "@/lib/format"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { PageShell } from "@/components/shared/PageShell"
import { SummaryStrip } from "@/components/dashboard/SummaryStrip"
import { DashboardSkeleton } from "@/components/dashboard/DashboardSkeleton"
import { MonthNavigator } from "@/components/dashboard/MonthNavigator"
import { ExpenseDonutChart } from "@/components/dashboard/charts/ExpenseDonutChart"
import { IncomeBarChart } from "@/components/dashboard/charts/IncomeBarChart"
import { SpendBarChart } from "@/components/dashboard/charts/SpendBarChart"
import { CollapsibleSections } from "@/components/dashboard/CollapsibleSections"
import QuickAddPicker from "@/components/QuickAddPicker"

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

const EXPENSE_TYPES: CategoryType[] = [
  "bill",
  "variable_expense",
  "debt",
  "saving",
  "investment",
]

const CATEGORY_TYPES_ALL: CategoryType[] = [
  "income",
  "bill",
  "variable_expense",
  "debt",
  "saving",
  "investment",
]

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function isOverBudget(type: CategoryType, budgeted: number, actual: number): boolean {
  if (type === "income" || type === "saving" || type === "investment") {
    return actual < budgeted  // under-earned / under-saved
  }
  return actual > budgeted    // overspent
}

// ---------------------------------------------------------------------------
// Dashboard inner — rendered once a budget id is known
// ---------------------------------------------------------------------------

function DashboardContent({ budgetId }: { budgetId: string }) {
  const { t } = useTranslation()
  const { budget, items, loading } = useBudgetDetail(budgetId)

  // ------------------------------------------------------------------
  // Derived totals — all hooks must be called before any early returns
  // ------------------------------------------------------------------

  const totalIncome = useMemo(
    () =>
      items
        .filter((i) => i.category?.type === "income")
        .reduce((sum, i) => sum + i.actual_amount, 0),
    [items]
  )

  const totalExpenses = useMemo(
    () =>
      items
        .filter((i) => i.category?.type !== "income")
        .reduce((sum, i) => sum + i.actual_amount, 0),
    [items]
  )

  const budgetedIncome = useMemo(
    () =>
      items
        .filter((i) => i.category?.type === "income")
        .reduce((sum, i) => sum + i.budgeted_amount, 0),
    [items]
  )

  const budgetedExpenses = useMemo(
    () =>
      items
        .filter((i) => i.category?.type !== "income")
        .reduce((sum, i) => sum + i.budgeted_amount, 0),
    [items]
  )

  // ------------------------------------------------------------------
  // Chart data derivations (memoized)
  // ------------------------------------------------------------------

  const pieData = useMemo(
    () =>
      EXPENSE_TYPES.map((type) => {
        const total = items
          .filter((i) => i.category?.type === type)
          .reduce((sum, i) => sum + i.actual_amount, 0)
        return { type, value: total, label: t(`categories.types.${type}`) }
      }).filter((d) => d.value > 0),
    [items, t]
  )

  const incomeBarData = useMemo(() => {
    const budgeted = items
      .filter((i) => i.category?.type === "income")
      .reduce((sum, i) => sum + i.budgeted_amount, 0)
    const actual = items
      .filter((i) => i.category?.type === "income")
      .reduce((sum, i) => sum + i.actual_amount, 0)
    if (budgeted === 0 && actual === 0) return []
    return [{ label: t("categories.types.income"), budgeted, actual }]
  }, [items, t])

  const spendBarData = useMemo(
    () =>
      EXPENSE_TYPES.map((type) => {
        const groupItems = items.filter((i) => i.category?.type === type)
        if (groupItems.length === 0) return null
        const budgeted = groupItems.reduce((sum, i) => sum + i.budgeted_amount, 0)
        const actual = groupItems.reduce((sum, i) => sum + i.actual_amount, 0)
        return { type, label: t(`categories.types.${type}`), budgeted, actual }
      }).filter(Boolean) as Array<{
        type: string
        label: string
        budgeted: number
        actual: number
      }>,
    [items, t]
  )

  const groupedSections = useMemo(() =>
    CATEGORY_TYPES_ALL
      .map((type) => {
        const groupItems = items.filter((i) => i.category?.type === type)
        if (groupItems.length === 0) return null
        const budgeted = groupItems.reduce((s, i) => s + i.budgeted_amount, 0)
        const actual = groupItems.reduce((s, i) => s + i.actual_amount, 0)
        return {
          type,
          label: t(`categories.types.${type}`),
          items: groupItems,
          budgeted,
          actual,
        }
      })
      .filter((g): g is NonNullable<typeof g> => g !== null),
    [items, t]
  )

  const [openSections, setOpenSections] = useState<Record<string, boolean>>(() =>
    Object.fromEntries(
      groupedSections.map((g) => [g.type, isOverBudget(g.type, g.budgeted, g.actual)])
    )
  )
  // Note: state resets automatically on month navigation because DashboardContent
  // is keyed by budgetId in DashboardPage (key={budgetId} causes full remount)

  // ------------------------------------------------------------------
  // Early returns after all hooks
  // ------------------------------------------------------------------

  if (loading) return <DashboardSkeleton />
  if (!budget) return null

  const handleToggleSection = (type: string, open: boolean) => {
    setOpenSections((prev) => ({ ...prev, [type]: open }))
  }

  const currency = budget.currency
  const availableBalance = totalIncome - totalExpenses + budget.carryover_amount

  const carryover = budget.carryover_amount
  const carryoverSubtitle = carryover !== 0
    ? t("dashboard.carryoverIncludes", { amount: formatCurrency(Math.abs(carryover), currency) })
    : undefined
  const carryoverIsNegative = carryover < 0

  return (
    <div className="space-y-8">
      {/* Summary cards */}
      <SummaryStrip
        income={{
          value: formatCurrency(totalIncome, currency),
          budgeted: formatCurrency(budgetedIncome, currency),
        }}
        expenses={{
          value: formatCurrency(totalExpenses, currency),
          budgeted: formatCurrency(budgetedExpenses, currency),
        }}
        balance={{
          value: formatCurrency(availableBalance, currency),
          isPositive: availableBalance >= 0,
          carryoverSubtitle,
          carryoverIsNegative,
        }}
        t={t}
      />

      {/* 3-column chart grid */}
      <div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
        <Card>
          <CardHeader>
            <CardTitle className="text-base">{t("dashboard.expenseDonut")}</CardTitle>
          </CardHeader>
          <CardContent>
            <ExpenseDonutChart
              data={pieData}
              totalExpenses={totalExpenses}
              currency={currency}
              emptyMessage={t("dashboard.noData")}
            />
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle className="text-base">{t("dashboard.incomeChart")}</CardTitle>
          </CardHeader>
          <CardContent>
            <IncomeBarChart
              data={incomeBarData}
              currency={currency}
              emptyMessage={t("dashboard.noData")}
            />
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle className="text-base">{t("dashboard.spendChart")}</CardTitle>
          </CardHeader>
          <CardContent>
            <SpendBarChart
              data={spendBarData}
              currency={currency}
              emptyMessage={t("dashboard.noData")}
            />
          </CardContent>
        </Card>
      </div>

      {/* Collapsible category sections */}
      {groupedSections.length > 0 && (
        <CollapsibleSections
          groups={groupedSections}
          currency={currency}
          openSections={openSections}
          onToggleSection={handleToggleSection}
          t={t}
        />
      )}

      {/* Quick Add button */}
      <div className="flex justify-end">
        <QuickAddPicker budgetId={budgetId} />
      </div>
    </div>
  )
}

// ---------------------------------------------------------------------------
// DashboardPage
// ---------------------------------------------------------------------------

export default function DashboardPage() {
  const { t } = useTranslation()
  const { isFirstRun, loading: firstRunLoading } = useFirstRunState()
  const { month } = useMonthParam()
  const { budgets, loading, createBudget, generateFromTemplate } = useBudgets()

  const availableMonths = useMemo(
    () => budgets.map((b) => b.start_date.slice(0, 7)),
    [budgets]
  )

  const currentBudget = useMemo(
    () => budgets.find((b) => b.start_date.startsWith(month)),
    [budgets, month]
  )

  const [parsedYear, parsedMonth] = month.split("-").map(Number)

  if (firstRunLoading) return <DashboardSkeleton />
  if (isFirstRun) return <Navigate to="/setup" replace />

  return (
    <PageShell
      title={t("dashboard.title")}
      action={<MonthNavigator availableMonths={availableMonths} t={t} />}
    >
      {loading ? (
        <DashboardSkeleton />
      ) : !currentBudget ? (
        /* No budget for the selected month */
        <div className="flex flex-col items-center gap-4 py-20 text-center">
          <p className="text-muted-foreground">{t("dashboard.noBudgetForMonth")}</p>
          <div className="flex gap-3">
            <Button
              variant="default"
              onClick={() =>
                createBudget.mutate({
                  month: parsedMonth,
                  year: parsedYear,
                  currency: "EUR",
                })
              }
              disabled={createBudget.isPending}
            >
              {t("dashboard.createBudget")}
            </Button>
            <Button
              variant="outline"
              onClick={() =>
                generateFromTemplate.mutate({
                  month: parsedMonth,
                  year: parsedYear,
                  currency: "EUR",
                })
              }
              disabled={generateFromTemplate.isPending}
            >
              {t("dashboard.generateFromTemplate")}
            </Button>
          </div>
        </div>
      ) : (
        <DashboardContent key={currentBudget.id} budgetId={currentBudget.id} />
      )}
    </PageShell>
  )
}
