"use client";

import * as React from "react";
import { BanIcon, SparklesIcon, TagIcon } from "lucide-react";

import { EmptyState } from "@/components/ui/empty-state";
import { Switch } from "@/components/ui/switch";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Typography } from "@/components/ui/typography";
import { DataTable, useDataTableQuery } from "@/components/data-table";
import type { DataTableColumn } from "@/components/data-table";
import { useProviderPackages } from "@/hooks/catalog/useProviderPackages";
import { usePriceFormat } from "@/hooks/usePriceFormat";
import { useTranslation } from "@/hooks/useTranslation";
import { getPackageIcon } from "@/lib/constants/package-icons";
import type { ProviderPackage } from "@/types/catalog";

import { ServiceOptOutDialog } from "./ServiceOptOutDialog";
import { ServicePriceDialog } from "./ServicePriceDialog";

const OFFERED_TABS = ["ALL", "OFFERED", "AVAILABLE"] as const;
type OfferedFilter = (typeof OFFERED_TABS)[number];

/** `undefined` = no filter; the api layer stringifies the boolean */
const IS_OFFERED_PARAM: Record<OfferedFilter, boolean | undefined> = {
  ALL: undefined,
  OFFERED: true,
  AVAILABLE: false,
};

/**
 * The provider's own service list, assembled from the admin catalog.
 *
 * Providers don't create services — the admin defines each package and the
 * price range it may be sold at, and this screen is where a provider opts into
 * the ones it offers and sets its price inside that range
 * (`Notes/requitements/01_changes.txt`). Everything a customer can book from
 * this provider starts here.
 *
 * Server mode: the backend owns search/filter/pagination. Columns are NOT
 * marked sortable — `GET /catalog/provider/packages` has no sort parameter (it
 * hardcodes `name asc`), and its `forbidNonWhitelisted` validation would 400 on
 * an unexpected query key.
 *
 * The switch never writes directly: enabling needs a price (the backend rejects
 * `optIn: true` without one) and disabling destroys the stored price, so both
 * directions go through a dialog.
 */
export function ProviderServicesView() {
  const { t } = useTranslation();
  const { formatPrice, formatPriceRange } = usePriceFormat();

  const { query, setQuery } = useDataTableQuery();
  const [offeredFilter, setOfferedFilter] =
    React.useState<OfferedFilter>("ALL");
  const [priceTarget, setPriceTarget] = React.useState<ProviderPackage | null>(
    null,
  );
  const [optOutTarget, setOptOutTarget] =
    React.useState<ProviderPackage | null>(null);

  const { data, isLoading, isError, refetch } = useProviderPackages({
    search: query.search,
    isOffered: IS_OFFERED_PARAM[offeredFilter],
    page: query.page,
    limit: query.pageSize,
  });

  function handleOfferedFilterChange(next: OfferedFilter) {
    setOfferedFilter(next);
    // A page-2 view of "all" is meaningless once the filter narrows the set.
    setQuery({ ...query, page: 1 });
  }

  const columns = React.useMemo<DataTableColumn<ProviderPackage>[]>(
    () => [
      {
        // First column doubles as the mobile card title — keep it identifying.
        key: "name",
        header: t("catalog.columns.package"),
        cell: (pkg) => {
          const Icon = getPackageIcon(pkg.icon);
          return (
            <div className="flex min-w-0 items-center gap-2">
              <span className="flex size-9 shrink-0 items-center justify-center rounded-[12px] bg-information-light text-primary-sky-blue">
                <Icon className="size-4" />
              </span>
              <div className="flex min-w-0 flex-col gap-1">
                <Typography as="span" variant="body" className="truncate">
                  {pkg.name}
                </Typography>
                {pkg.description && (
                  <Typography
                    as="span"
                    variant="caption"
                    color="secondary"
                    className="truncate"
                  >
                    {pkg.description}
                  </Typography>
                )}
              </div>
            </div>
          );
        },
      },
      {
        key: "duration",
        header: t("catalog.columns.duration"),
        cell: (pkg) => (
          <Typography as="span" variant="number">
            {t("catalog.minutes", { count: pkg.estimatedDuration })}
          </Typography>
        ),
      },
      {
        key: "priceRange",
        header: t("catalog.myServices.columns.allowedRange"),
        hideOnMobile: true,
        cell: (pkg) => (
          <Typography as="span" variant="caption" color="secondary">
            {pkg.minPrice === pkg.maxPrice
              ? formatPrice(pkg.minPrice)
              : formatPriceRange(pkg.minPrice, pkg.maxPrice)}
          </Typography>
        ),
      },
      {
        key: "price",
        header: t("catalog.myServices.columns.myPrice"),
        cell: (pkg) =>
          pkg.price === null ? (
            <Typography as="span" variant="caption" color="secondary">
              {t("catalog.myServices.notSet")}
            </Typography>
          ) : (
            <Typography as="span" variant="number">
              {formatPrice(pkg.price)}
            </Typography>
          ),
      },
      {
        key: "isOffered",
        header: t("catalog.myServices.columns.offering"),
        align: "end",
        cell: (pkg) => (
          <Switch
            checked={pkg.isOffered}
            aria-label={t("catalog.myServices.columns.offering")}
            // Enabling needs a price and disabling destroys one — neither is a
            // silent write, so the switch only opens the matching dialog.
            onCheckedChange={(checked) =>
              checked ? setPriceTarget(pkg) : setOptOutTarget(pkg)
            }
          />
        ),
      },
    ],
    [t, formatPrice, formatPriceRange],
  );

  return (
    <div className="flex flex-col gap-6">
      {/* py-1 keeps the active pill's shadow from being clipped by the
          scroll container (setting overflow-x also computes overflow-y). */}
      <Tabs
        value={offeredFilter}
        onValueChange={(value) =>
          handleOfferedFilterChange(value as OfferedFilter)
        }
      >
        <div className="overflow-x-auto py-1">
          <TabsList>
            {OFFERED_TABS.map((tab) => (
              <TabsTrigger key={tab} value={tab}>
                {t(`catalog.myServices.filters.${tab}`)}
              </TabsTrigger>
            ))}
          </TabsList>
        </div>
      </Tabs>

      <DataTable
        mode="server"
        columns={columns}
        data={data?.data ?? []}
        totalCount={data?.total ?? 0}
        getRowId={(pkg) => pkg.id}
        query={query}
        onQueryChange={setQuery}
        searchable
        searchPlaceholder={t("catalog.searchPlaceholder")}
        loading={isLoading}
        error={isError}
        onRetry={() => refetch()}
        rowActions={(pkg) =>
          pkg.isOffered
            ? [
                {
                  key: "editPrice",
                  label: t("catalog.myServices.actions.changePrice"),
                  icon: <TagIcon />,
                  onSelect: () => setPriceTarget(pkg),
                },
                {
                  key: "optOut",
                  label: t("catalog.myServices.actions.stopOffering"),
                  icon: <BanIcon />,
                  destructive: true,
                  onSelect: () => setOptOutTarget(pkg),
                },
              ]
            : [
                {
                  key: "optIn",
                  label: t("catalog.myServices.actions.startOffering"),
                  icon: <SparklesIcon />,
                  onSelect: () => setPriceTarget(pkg),
                },
              ]
        }
        // Only override the empty state when nothing is being filtered out —
        // with a search or a tab active, the DataTable's own "no results" copy
        // is the correct message, so leave it undefined and let it win.
        emptyState={
          offeredFilter === "ALL" && !query.search.trim() ? (
            <EmptyState
              icon={<SparklesIcon />}
              title={t("catalog.myServices.emptyTitle")}
              description={t("catalog.myServices.emptyDescription")}
            />
          ) : undefined
        }
      />

      <ServicePriceDialog
        target={priceTarget}
        onClose={() => setPriceTarget(null)}
      />

      <ServiceOptOutDialog
        target={optOutTarget}
        onClose={() => setOptOutTarget(null)}
      />
    </div>
  );
}
