"use client";

import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { Building2, Map, MapPin, Plus, Trash2 } from "lucide-react";
import { ConfirmDialog } from "@/components/shared/confirm-dialog";
import { EmptyState, ErrorState, TableSkeleton } from "@/components/shared/states";
import { StatusBadge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { CityDialog } from "@/features/cities/city-dialog";
import { useCan } from "@/features/auth/use-can";
import { useI18n, useT } from "@/i18n";
import { friendlyErrorMessage } from "@/lib/errors";
import { formatCurrency, formatNumber } from "@/lib/format";
import { queryKeys } from "@/lib/query-keys";
import { deleteCity, flattenCities, getCities } from "@/services/cities";
import type { City } from "@/types/city";

/**
 * Where the company delivers, and what a delivery there earns.
 *
 * **Districts are drawn under their city, indented, and the rate says where it came from.** The
 * inheritance is the point of the screen: a district marked as following its city changes when the
 * city changes, and one with its own rate does not. A table that showed only figures would make those
 * two look identical and the next rate change a surprise.
 */
export function CityTree({ currency }: { currency: string }) {
  const t = useT();
  const { locale } = useI18n();
  const { can } = useCan();
  const canManage = can("cities.manage");

  const queryClient = useQueryClient();

  const { data, isLoading, isError, error, refetch } = useQuery({
    queryKey: queryKeys.cities.tree,
    queryFn: async () => (await getCities()).Model ?? [],
  });

  const cities = data ?? [];
  const rows = flattenCities(cities);

  const [dialog, setDialog] = useState<
    | { kind: "city" }
    | { kind: "district"; parent: City }
    | { kind: "edit"; city: City; parent: City | null }
    | null
  >(null);
  const [removing, setRemoving] = useState<City | null>(null);

  const remove = useMutation({
    mutationFn: (city: City) => deleteCity(city.uuid),
    onSuccess: (response) => {
      toast.success(response.Message ?? t("cities.removed"));
      setRemoving(null);
      void queryClient.invalidateQueries({ queryKey: queryKeys.cities.all });
    },
    // The server refuses a city with districts, and an area captains have been paid for. Its message
    // says which, and it is the answer the operator needs — not a generic failure.
    onError: (err) => toast.error(friendlyErrorMessage(err, t)),
  });

  return (
    <div className="space-y-4">
      <Card>
        <div className="flex flex-wrap items-center justify-between gap-3 border-b p-4">
          <p className="text-sm text-muted-foreground">{t("cities.hint")}</p>
          {canManage ? (
            <Button size="sm" onClick={() => setDialog({ kind: "city" })}>
              <Plus className="me-1.5 h-4 w-4" aria-hidden />
              {t("cities.addCity")}
            </Button>
          ) : null}
        </div>

        {isLoading ? (
          <TableSkeleton rows={6} cols={5} />
        ) : isError ? (
          <ErrorState message={friendlyErrorMessage(error, t)} onRetry={() => refetch()} />
        ) : rows.length === 0 ? (
          <EmptyState title={t("cities.empty")} description={t("cities.emptyHint")} icon={Map} />
        ) : (
          <div className="overflow-x-auto">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>{t("cities.area")}</TableHead>
                  <TableHead className="text-end">{t("cities.earning")}</TableHead>
                  <TableHead className="text-end">{t("cities.freelanceShare")}</TableHead>
                  <TableHead>{t("cities.rateSource")}</TableHead>
                  <TableHead>{t("cities.reach")}</TableHead>
                  <TableHead aria-label={t("common.actions")} />
                </TableRow>
              </TableHeader>
              <TableBody>
                {rows.map(({ city, depth }) => {
                  const parent =
                    depth === 1
                      ? (cities.find((candidate) => candidate.uuid === city.parent_uuid) ?? null)
                      : null;

                  return (
                    <TableRow key={city.uuid} className={city.is_active ? undefined : "opacity-60"}>
                      <TableCell>
                        <span
                          className={
                            depth === 1 ? "flex items-center gap-2 ps-6" : "flex items-center gap-2"
                          }
                        >
                          {depth === 1 ? (
                            <MapPin className="h-3.5 w-3.5 text-muted-foreground" aria-hidden />
                          ) : (
                            <Building2 className="h-4 w-4 text-muted-foreground" aria-hidden />
                          )}
                          <span className={depth === 0 ? "font-medium" : undefined}>
                            {city.name}
                          </span>
                          {!city.is_active ? (
                            <StatusBadge variant="secondary">{t("cities.inactive")}</StatusBadge>
                          ) : null}
                        </span>
                      </TableCell>

                      <TableCell className="numeric text-end font-medium">
                        {formatCurrency(city.delivery_earning, currency, locale)}
                      </TableCell>

                      {/*
                        What a freelancer keeps of the figure beside it. Shown as a percentage and
                        then as money, because the percentage is the decision and the money is what
                        a captain will ask about.
                      */}
                      <TableCell className="numeric whitespace-nowrap text-end">
                        <span className="font-medium">
                          {formatNumber(Math.round(city.freelance_share * 100), locale)}%
                        </span>
                        <span className="ms-2 text-xs text-muted-foreground">
                          {formatCurrency(
                            city.delivery_earning * city.freelance_share,
                            currency,
                            locale,
                          )}
                        </span>
                      </TableCell>

                      <TableCell>
                        {/*
                          The field the whole screen turns on. "Follows the city" is informational;
                          "its own rate" is a decision a later city edit must ask about, and it reads
                          differently on purpose.
                        */}
                        <StatusBadge
                          variant={city.earning_source === "own" ? "info" : "secondary"}
                          >
                          {city.earning_source === "own"
                            ? t("cities.source.own")
                            : t("cities.source.inherited")}
                        </StatusBadge>
                      </TableCell>

                      <TableCell className="text-xs text-muted-foreground">
                        {t("cities.radiusValue", {
                          km: formatNumber(
                            Math.round((city.radius_m / 1000) * 10) / 10,
                            locale,
                          ),
                        })}
                        {depth === 0 && (city.districts_with_own_earning ?? 0) > 0 ? (
                          <span className="mt-0.5 block">
                            {t("cities.ownRateCount", {
                              count: formatNumber(city.districts_with_own_earning ?? 0, locale),
                            })}
                          </span>
                        ) : null}
                      </TableCell>

                      <TableCell>
                        <div className="flex items-center justify-end gap-2">
                          {canManage ? (
                            <>
                              {depth === 0 ? (
                                <Button
                                  size="sm"
                                  variant="ghost"
                                  onClick={() => setDialog({ kind: "district", parent: city })}
                                >
                                  <Plus className="me-1 h-3.5 w-3.5" aria-hidden />
                                  {t("cities.addDistrict")}
                                </Button>
                              ) : null}
                              <Button
                                size="sm"
                                variant="outline"
                                onClick={() => setDialog({ kind: "edit", city, parent })}
                              >
                                {t("common.edit")}
                              </Button>
                              <Button
                                size="sm"
                                variant="ghost"
                                aria-label={t("cities.remove")}
                                onClick={() => setRemoving(city)}
                              >
                                <Trash2 className="h-4 w-4 text-destructive" aria-hidden />
                              </Button>
                            </>
                          ) : null}
                        </div>
                      </TableCell>
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          </div>
        )}
      </Card>

      {dialog ? (
        <CityDialog
          open
          onOpenChange={(open) => {
            if (!open) setDialog(null);
          }}
          mode={dialog}
          currency={currency}
        />
      ) : null}

      {removing ? (
        <ConfirmDialog
          open
          onOpenChange={(open) => {
            if (!open) setRemoving(null);
          }}
          title={t("cities.removeTitle")}
          description={t("cities.removeBody", { name: removing.name })}
          confirmLabel={t("cities.remove")}
          destructive
          loading={remove.isPending}
          onConfirm={() => remove.mutate(removing)}
        />
      ) : null}
    </div>
  );
}
