"use client";

import { useMemo } from "react";
import Link from "next/link";
import { useQuery } from "@tanstack/react-query";
import { CircleDollarSign, MapPinOff, TriangleAlert } from "lucide-react";
import { Pagination } from "@/components/shared/pagination";
import { EmptyState, ErrorState, TableSkeleton } from "@/components/shared/states";
import { StatusBadge } from "@/components/ui/badge";
import { Card } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { useI18n, useT } from "@/i18n";
import { friendlyErrorMessage } from "@/lib/errors";
import { formatCurrency, formatDateTime, formatNumber } from "@/lib/format";
import { queryKeys } from "@/lib/query-keys";
import { useUrlState } from "@/lib/use-url-state";
import { EARNING_STATUSES, getDeliveryEarnings } from "@/services/cities";
import { keyedMap } from "@/services/ledger";
import type { DeliveryEarningStatus, EarningTotals } from "@/types/city";

/**
 * What deliveries have earned captains, and what each area cost.
 *
 * **The deliveries that earned nothing are in here, not hidden.** A drop-off that matched no area pays
 * nothing, and that row is two things at once: money a captain will ask about, and the map of where a
 * district is missing. The unresolved count sits beside the money for the same reason — a week that
 * looks cheap because eleven deliveries never resolved is a different problem from a quiet week.
 *
 * Nothing here is recalculated. Every figure was written when the delivery landed, so the report can
 * never disagree with the balance it explains.
 */
export function EarningsReport() {
  const t = useT();
  const { locale } = useI18n();

  const [page, setPage] = useUrlState("epage", 1, (value) => {
    const parsed = Number(value);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
  });
  const [status, setStatus] = useUrlState<DeliveryEarningStatus | "">("status", "", (value) =>
    EARNING_STATUSES.includes(value as DeliveryEarningStatus)
      ? (value as DeliveryEarningStatus)
      : "",
  );
  const [from, setFrom] = useUrlState("efrom", "", (value) => value);
  const [to, setTo] = useUrlState("eto", "", (value) => value);

  // Refused by the server, and the message belongs beside the fields rather than a round trip away.
  const backwards = from !== "" && to !== "" && from > to;

  const filters = useMemo(
    () => ({
      page,
      rows: 20,
      status: status || undefined,
      from: from || undefined,
      to: to || undefined,
    }),
    [page, status, from, to],
  );

  const { data, isLoading, isError, error, refetch } = useQuery({
    queryKey: queryKeys.cities.earnings(filters),
    queryFn: () => getDeliveryEarnings(filters),
    enabled: !backwards,
  });

  const earnings = data?.Model ?? [];
  const totals = keyedMap(data?.Totals);
  const currencies = Object.keys(totals).sort();
  const byCity = data?.ByCity ?? [];

  return (
    <div className="space-y-4">
      {currencies.length > 0 ? (
        <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
          {currencies.map((code) => (
            <EarnedCard key={code} currency={code} totals={totals[code]} locale={locale} />
          ))}
        </div>
      ) : null}

      <Card>
        <div className="flex flex-wrap items-end justify-between gap-3 border-b p-4">
          <p className="basis-full text-sm text-muted-foreground sm:basis-auto">
            {t("earnings.hint")}
          </p>

          <div className="flex flex-wrap items-end gap-2">
            <div className="space-y-1.5">
              <Label htmlFor="earnings-status">{t("earnings.status")}</Label>
              <Select
                value={status || "all"}
                onValueChange={(value) => {
                  setStatus(value === "all" ? "" : (value as DeliveryEarningStatus));
                  setPage(1);
                }}
              >
                <SelectTrigger id="earnings-status" className="w-[13rem]">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="all">{t("earnings.allStatuses")}</SelectItem>
                  {EARNING_STATUSES.map((option) => (
                    <SelectItem key={option} value={option}>
                      {t(`earnings.statusValue.${option}`)}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>

            <div className="space-y-1.5">
              <Label htmlFor="earnings-from">{t("earnings.from")}</Label>
              <Input
                id="earnings-from"
                type="date"
                value={from}
                onChange={(event) => {
                  setFrom(event.target.value);
                  setPage(1);
                }}
                className="w-[10rem]"
              />
            </div>

            <div className="space-y-1.5">
              <Label htmlFor="earnings-to">{t("earnings.to")}</Label>
              <Input
                id="earnings-to"
                type="date"
                value={to}
                onChange={(event) => {
                  setTo(event.target.value);
                  setPage(1);
                }}
                className="w-[10rem]"
                aria-invalid={backwards}
              />
            </div>
          </div>
        </div>

        {backwards ? (
          <div className="p-4">
            <p className="text-sm text-destructive">{t("earnings.backwardsWindow")}</p>
          </div>
        ) : isLoading ? (
          <TableSkeleton rows={8} cols={5} />
        ) : isError ? (
          <ErrorState message={friendlyErrorMessage(error, t)} onRetry={() => refetch()} />
        ) : earnings.length === 0 ? (
          <EmptyState
            title={t("earnings.empty")}
            description={t("earnings.emptyHint")}
            icon={CircleDollarSign}
          />
        ) : (
          <>
            <div className="overflow-x-auto">
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead>{t("earnings.captain")}</TableHead>
                    <TableHead>{t("earnings.area")}</TableHead>
                    <TableHead className="text-end">{t("earnings.amount")}</TableHead>
                    <TableHead>{t("earnings.order")}</TableHead>
                    <TableHead>{t("earnings.when")}</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {earnings.map((earning) => (
                    <TableRow key={earning.uuid}>
                      <TableCell>
                        {earning.captain ? (
                          <Link
                            href={`/payments/captains/${earning.captain.uuid}`}
                            className="font-medium text-foreground hover:underline"
                          >
                            {earning.captain.name}
                          </Link>
                        ) : (
                          <span className="italic text-muted-foreground">
                            {t("ledger.unknownCaptain")}
                          </span>
                        )}
                      </TableCell>

                      <TableCell>
                        {earning.city ? (
                          <>
                            <span>{earning.city.name}</span>
                            {earning.city.parent_name ? (
                              <span className="block text-xs text-muted-foreground">
                                {earning.city.parent_name}
                              </span>
                            ) : null}
                          </>
                        ) : (
                          // Not a dash: this row is the reason to read the report.
                          <span className="flex items-center gap-1.5 text-xs text-warning">
                            <MapPinOff className="h-3.5 w-3.5" aria-hidden />
                            {t("earnings.noArea")}
                            {earning.lat !== null && earning.lng !== null ? (
                              <span className="text-muted-foreground" dir="ltr">
                                {earning.lat.toFixed(4)}, {earning.lng.toFixed(4)}
                              </span>
                            ) : (
                              <span className="text-muted-foreground">
                                {t("earnings.noCoordinates")}
                              </span>
                            )}
                          </span>
                        )}
                      </TableCell>

                      <TableCell className="numeric text-end font-medium">
                        {earning.status === "credited" ? (
                          formatCurrency(earning.amount, earning.currency, locale)
                        ) : (
                          <StatusBadge variant="warning">{earning.status_label}</StatusBadge>
                        )}
                      </TableCell>

                      <TableCell>
                        {earning.order ? (
                          <Link
                            href={`/orders/${earning.order.uuid}`}
                            className="text-xs font-medium text-primary hover:underline"
                          >
                            {earning.order.order_number}
                          </Link>
                        ) : (
                          "—"
                        )}
                      </TableCell>

                      <TableCell className="text-xs text-muted-foreground">
                        {formatDateTime(earning.created_at, locale)}
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </div>
            <Pagination
              page={data!.Page}
              totalPages={data!.Total}
              records={data!.Records}
              onPageChange={(next) => setPage(next)}
            />
          </>
        )}
      </Card>

      {/*
        What each area cost, largest first — the question a rate is set to answer. Kept beside the
        rows rather than on its own screen, because "is this district worth 8,000 a delivery" is read
        against the deliveries that produced the figure.
      */}
      {byCity.length > 0 ? (
        <Card>
          <div className="border-b p-4">
            <p className="text-sm font-medium">{t("earnings.byArea")}</p>
            <p className="mt-0.5 text-xs text-muted-foreground">{t("earnings.byAreaHint")}</p>
          </div>
          <div className="overflow-x-auto">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>{t("earnings.area")}</TableHead>
                  <TableHead className="text-end">{t("earnings.deliveries")}</TableHead>
                  <TableHead className="text-end">{t("earnings.earned")}</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {byCity.map((row, index) => (
                  <TableRow key={`${row.city ?? "none"}-${row.currency}-${index}`}>
                    <TableCell>
                      {row.city ?? (
                        <span className="flex items-center gap-1.5 text-warning">
                          <TriangleAlert className="h-3.5 w-3.5" aria-hidden />
                          {t("earnings.noArea")}
                        </span>
                      )}
                      {row.parent ? (
                        <span className="block text-xs text-muted-foreground">{row.parent}</span>
                      ) : null}
                    </TableCell>
                    <TableCell className="numeric text-end text-muted-foreground">
                      {formatNumber(row.deliveries, locale)}
                    </TableCell>
                    <TableCell className="numeric text-end font-medium">
                      {formatCurrency(row.earned, row.currency, locale)}
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </div>
        </Card>
      ) : null}
    </div>
  );
}

/**
 * What one currency's filtered set came to.
 *
 * The unresolved count sits under the money deliberately: it is the figure that says whether the
 * number above it can be trusted as "what we paid for the work we did".
 */
function EarnedCard({
  currency,
  totals,
  locale,
}: {
  currency: string;
  totals: EarningTotals;
  locale: "en" | "ar";
}) {
  const t = useT();

  return (
    <Card className="p-4">
      <div className="flex items-start justify-between gap-2">
        <div>
          <p className="text-xs text-muted-foreground">{t("earnings.totalEarned")}</p>
          <p className="mt-1 text-2xl font-semibold text-primary">
            {formatCurrency(totals.earned, currency, locale)}
          </p>
          <p className="mt-0.5 text-xs text-muted-foreground">
            {t("earnings.deliveryCount", { count: formatNumber(totals.deliveries, locale) })}
          </p>
          {totals.unresolved > 0 ? (
            <p className="mt-1 flex items-center gap-1.5 text-xs text-warning">
              <TriangleAlert className="h-3.5 w-3.5" aria-hidden />
              {t("earnings.unresolvedCount", {
                count: formatNumber(totals.unresolved, locale),
              })}
            </p>
          ) : null}
        </div>
        <CircleDollarSign className="h-5 w-5 text-primary" aria-hidden />
      </div>
    </Card>
  );
}
