"use client"

import { useEffect, useState } from "react"
import Link from "next/link"
import { ArrowLeft, Wallet } from "lucide-react"

import { reportsApi } from "@/lib/api/general-ledger"
import { errorMessage } from "@/lib/error-map"
import { formatReportDate, startOfMonthIso, todayIso } from "@/lib/format"
import { cn } from "@/lib/utils"
import {
  CashFlowFinancingActivities,
  CashFlowInvestingActivities,
  CashFlowResponse,
  ReportType,
} from "@/types/general-ledger"

import { buttonVariants } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Skeleton } from "@/components/ui/skeleton"
import { DownloadCsvButton } from "@/components/reports/DownloadCsvButton"
import { DownloadPdfButton } from "@/components/reports/DownloadPdfButton"
import { ReportHeader } from "@/components/reports/ReportHeader"
import { ReportSection, ReportSectionLine } from "@/components/reports/ReportSection"
import { ReportSubtotal } from "@/components/reports/ReportSubtotal"

/**
 * Combines `operatingActivities.nonCashAdjustments` + `.workingCapitalChanges` into one labeled
 * set, then buckets by sign — per docs/21-GENERAL-LEDGER-FRONTEND.md §3: "Additions to Cash"
 * (amount >= 0) and "Subtractions From Cash" (amount < 0). A working-capital line's label uses its
 * `direction` field ("Decrease in Trade Receivables"); a non-cash-adjustment line just prints its
 * plain `description` ("Depreciation"), no Increase/Decrease prefix.
 */
function bucketOperatingLines(report: CashFlowResponse): { additions: ReportSectionLine[]; subtractions: ReportSectionLine[] } {
  // GL omits these list fields entirely (rather than sending `[]`) when there's nothing to
  // report for the period, instead of an empty array — confirmed live, not just a type-safety guard.
  const operating = report.operatingActivities
  const combined: ReportSectionLine[] = [
    ...(operating?.nonCashAdjustments ?? []).map((a) => ({ label: a.description, amount: a.amount })),
    ...(operating?.workingCapitalChanges ?? []).map((w) => ({
      label: `${w.direction} in ${w.accountName}`,
      amount: w.changeAmount,
    })),
  ]
  return {
    additions: combined.filter((l) => l.amount >= 0),
    subtractions: combined.filter((l) => l.amount < 0),
  }
}

/** Same "GL omits empty list fields" defense as bucketOperatingLines — the section itself,
 * or just its `lines[]`, may be missing entirely rather than `{ lines: [], ...: 0 }`. */
function activitySectionLines(
  section?: CashFlowInvestingActivities | CashFlowFinancingActivities | null
): ReportSectionLine[] {
  return (section?.lines ?? []).map((l) => ({ label: l.description, amount: l.amount }))
}

export default function CashFlowPage() {
  const [periodStart, setPeriodStart] = useState(startOfMonthIso())
  const [periodEnd, setPeriodEnd] = useState(todayIso())
  const [report, setReport] = useState<CashFlowResponse | null>(null)
  const [error, setError] = useState<string | null>(null)

  // Clears stale results the instant the period changes, during the render that reacts to it —
  // not inside the effect below, which would be a synchronous setState-in-effect
  // (react-hooks/set-state-in-effect); this is React's own sanctioned "adjust state during
  // render" pattern instead.
  const periodKey = `${periodStart}|${periodEnd}`
  const [loadedFor, setLoadedFor] = useState<string | null>(null)
  if (loadedFor !== periodKey) {
    setLoadedFor(periodKey)
    setReport(null)
    setError(null)
  }

  useEffect(() => {
    if (!periodStart || !periodEnd) return
    let cancelled = false
    reportsApi
      .cashFlow(periodStart, periodEnd)
      .then((res) => {
        if (!cancelled) setReport(res)
      })
      .catch((err) => {
        if (!cancelled) setError(errorMessage(err))
      })
    return () => {
      cancelled = true
    }
  }, [periodStart, periodEnd])

  const buckets = report ? bucketOperatingLines(report) : null

  return (
    <div className="flex flex-col gap-6">
      <div className="flex items-center gap-3">
        <Link href="/dashboard/ledgers" className={cn(buttonVariants({ variant: "ghost", size: "icon-lg" }))}>
          <ArrowLeft className="size-5" />
        </Link>
        <div>
          <h1 className="text-2xl font-bold text-foreground">Cash Flow</h1>
          <p className="text-base text-muted-foreground">Statement of Cash Flows for a period.</p>
        </div>
      </div>

      <div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
        <div className="grid grid-cols-2 gap-3 sm:flex sm:items-end">
          <div className="flex flex-col gap-1.5">
            <Label className="text-base">From</Label>
            <Input type="date" value={periodStart} onChange={(e) => setPeriodStart(e.target.value)} className="h-11 text-base" />
          </div>
          <div className="flex flex-col gap-1.5">
            <Label className="text-base">To</Label>
            <Input type="date" value={periodEnd} onChange={(e) => setPeriodEnd(e.target.value)} className="h-11 text-base" />
          </div>
        </div>
        <div className="flex gap-2">
          <DownloadPdfButton reportType={ReportType.CashFlow} params={{ periodStart, periodEnd }} disabled={!report} />
          <DownloadCsvButton reportType={ReportType.CashFlow} params={{ periodStart, periodEnd }} disabled={!report} />
        </div>
      </div>

      {error && (
        <div className="rounded-lg border border-destructive/30 bg-destructive/5 p-5 text-base text-destructive">{error}</div>
      )}

      {!error && report === null && (
        <div className="flex flex-col gap-3">
          {Array.from({ length: 6 }).map((_, i) => (
            <Skeleton key={i} className="h-12 w-full" />
          ))}
        </div>
      )}

      {!error && report !== null && buckets !== null && (
        <div className="rounded-2xl bg-white p-6 shadow-sm ring-1 ring-black/5">
          <ReportHeader
            title="Statement of Cash Flows"
            subtitle={`For the period ${formatReportDate(periodStart)} to ${formatReportDate(periodEnd)}`}
          />

          <div className="mt-4">
            <ReportSubtotal label="Net Earnings" amount={report.operatingActivities?.profitForPeriod ?? 0} />
            <ReportSection title="Additions to Cash" lines={buckets.additions} />
            <ReportSection title="Subtractions From Cash" lines={buckets.subtractions} />
            <ReportSubtotal
              label="Net Cash From Operations"
              amount={report.operatingActivities?.netCashFromOperatingActivities ?? 0}
            />

            <ReportSection
              title="Investing Activities"
              lines={activitySectionLines(report.investingActivities)}
              total={
                (report.investingActivities?.lines?.length ?? 0) > 1
                  ? report.investingActivities?.netCashFromInvestingActivities
                  : undefined
              }
            />
            <ReportSection
              title="Financing Activities"
              lines={activitySectionLines(report.financingActivities)}
              total={
                (report.financingActivities?.lines?.length ?? 0) > 1
                  ? report.financingActivities?.netCashFromFinancingActivities
                  : undefined
              }
            />

            <ReportSubtotal label="Net Increase / Decrease in Cash" amount={report.netIncreaseDecreaseInCash} large />
          </div>

          <p className="mt-2 flex items-center gap-1.5 text-sm text-muted-foreground">
            <Wallet className="size-4" />
            Opening/closing cash balances are computed by the General Ledger service but not shown on this
            screen, matching GL&apos;s own PDF/CSV output.
          </p>
        </div>
      )}
    </div>
  )
}
