"use client";

import { Download, Eye, FileSearch, Loader2, RefreshCw, Search, X } from "lucide-react";
import * as React from "react";
import { toast } from "sonner";

import {
  downloadCustomerDeepdexDocument,
  fetchCustomerDeepdexListClient,
  getCustomerDeepdexViewUrl,
  searchCustomerDeepdexClient,
} from "@/app/customer/[tenant]/deepdex/_lib/deepdex-api";
import { DeepdexSearchResultItem } from "@/components/deepdex/components/deepdex-search-result-item";
import { DEEPDEX_DOC_TYPE_OPTIONS, getDeepdexDocTypeLabel } from "@/components/deepdex/data/deepdex-doc-types";
import { deepdexSettingsDefaults } from "@/components/deepdex/data/deepdex-settings.defaults";
import type {
  DeepdexDocument,
  DeepdexSearchFilters,
  DeepdexSearchResponse,
  DeepdexSettings,
} from "@/components/deepdex/types";
import { ErrorBanner } from "@/components/shared/error-banner";
import { resolveYiiListPageCount } from "@/lib/list-pagination";
import { TABLE_ROW_ICON_BTN, TABLE_TOOLBAR_BTN_OUTLINE } from "@/components/shared/table-ui";
import { Button } from "@/components/ui/button";
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 { formatFileSize } from "@/lib/format-file-size";
import { SETTINGS_INPUT_CLASS } from "@/components/settings/constants";
import { cn } from "@/lib/utils";

const emptyFilters: DeepdexSearchFilters = {
  docType: "",
  issuer: "",
  name: "",
  isin: "",
  productType: "",
  status: "",
};

function resolvePageCount(totalCount: number, pageSize: number, reportedPageCount?: number) {
  return resolveYiiListPageCount({
    totalCount,
    pageSize,
    paginationPageCount: reportedPageCount,
  });
}

type CustomerDeepdexPageProps = {
  tenant: string;
  initialItems: DeepdexDocument[];
  initialTotalCount: number;
  initialPage: number;
  initialPageSize: number;
  initialPageCount: number;
  initialSettings?: DeepdexSettings;
  initialErrorMessage?: string | null;
  permissionDenied?: boolean;
};

export function CustomerDeepdexPage({
  tenant,
  initialItems,
  initialTotalCount,
  initialPage,
  initialPageSize,
  initialPageCount,
  initialSettings = deepdexSettingsDefaults,
  initialErrorMessage = null,
  permissionDenied = false,
}: CustomerDeepdexPageProps) {
  const [items, setItems] = React.useState(initialItems);
  const [totalCount, setTotalCount] = React.useState(initialTotalCount);
  const [page, setPage] = React.useState(initialPage);
  const [pageSize] = React.useState(initialPageSize);
  const [pageCount, setPageCount] = React.useState(
    resolvePageCount(initialTotalCount, initialPageSize, initialPageCount),
  );
  const [settings] = React.useState({
    ...initialSettings,
    // Customer portal always offers view/download for assigned docs (legacy list parity).
    showViewBtn: true,
    showDownloadBtn: true,
  });
  const [listError, setListError] = React.useState(initialErrorMessage);
  const [isRefreshing, setIsRefreshing] = React.useState(false);
  const [downloadingId, setDownloadingId] = React.useState<string | null>(null);

  const [query, setQuery] = React.useState("");
  const [filters, setFilters] = React.useState<DeepdexSearchFilters>(emptyFilters);
  const [searchResponse, setSearchResponse] = React.useState<DeepdexSearchResponse | null>(null);
  const [isSearching, setIsSearching] = React.useState(false);
  const [searchError, setSearchError] = React.useState<string | null>(null);

  const hasSearchQuery = query.trim().length > 0;

  const refreshList = React.useCallback(
    async (nextPage = page) => {
      setIsRefreshing(true);
      setListError(null);
      try {
        const data = await fetchCustomerDeepdexListClient(tenant, {
          page: nextPage,
          pageSize,
        });
        setItems(data.items);
        setTotalCount(data.totalCount);
        setPage(nextPage);
        setPageCount(resolvePageCount(data.totalCount, data.pageSize || pageSize, data.pageCount));
      } catch (error) {
        setListError(error instanceof Error ? error.message : "Failed to load Deepdex documents");
      } finally {
        setIsRefreshing(false);
      }
    },
    [page, pageSize, tenant],
  );

  React.useEffect(() => {
    if (!hasSearchQuery) {
      setSearchResponse(null);
      setSearchError(null);
      setIsSearching(false);
      return;
    }

    const controller = new AbortController();
    const timer = window.setTimeout(() => {
      setIsSearching(true);
      setSearchError(null);
      void searchCustomerDeepdexClient(tenant, query.trim(), filters, controller.signal)
        .then((data) => {
          setSearchResponse(data);
        })
        .catch((error: unknown) => {
          if (controller.signal.aborted) return;
          setSearchResponse(null);
          setSearchError(error instanceof Error ? error.message : "Search failed");
        })
        .finally(() => {
          if (!controller.signal.aborted) setIsSearching(false);
        });
    }, 250);

    return () => {
      controller.abort();
      window.clearTimeout(timer);
    };
  }, [filters, hasSearchQuery, query, tenant]);

  const clearFilters = () => {
    setFilters(emptyFilters);
  };

  const resolveViewUrl = React.useCallback(
    (token: string) => getCustomerDeepdexViewUrl(tenant, token),
    [tenant],
  );

  const onDownloadDocument = React.useCallback(
    async (token: string, fileName: string) => {
      await downloadCustomerDeepdexDocument(tenant, token, fileName);
    },
    [tenant],
  );

  const handleRowDownload = async (doc: DeepdexDocument) => {
    const token = doc.downloadToken || doc.viewToken;
    if (!token) {
      toast.error("Download token is unavailable");
      return;
    }
    setDownloadingId(doc.id);
    try {
      await downloadCustomerDeepdexDocument(tenant, token, doc.originalName);
      toast.success(`Downloading "${doc.originalName}"`);
    } catch {
      toast.error("Failed to download document");
    } finally {
      setDownloadingId(null);
    }
  };

  if (permissionDenied) {
    return (
      <div className="flex flex-col gap-3 md:gap-4">
        <div className="flex items-center gap-2 border-b pb-3">
          <FileSearch className="size-5 text-violet-600" />
          <h1 className="font-semibold text-base tracking-tight">Deepdex</h1>
        </div>
        <ErrorBanner message="You do not have permission to access Deepdex." />
      </div>
    );
  }

  return (
    <div className="flex flex-col gap-3 md:gap-4">
      <div className="flex flex-col gap-2 border-b pb-3 sm:flex-row sm:items-center sm:justify-between">
        <div className="flex items-center gap-2">
          <FileSearch className="size-5 text-violet-600" />
          <h1 className="font-semibold text-base tracking-tight">Deepdex</h1>
        </div>
        <div className="flex items-center gap-2">
          <span className="text-muted-foreground text-xs">
            {totalCount} document{totalCount === 1 ? "" : "s"}
          </span>
          <Button
            type="button"
            {...TABLE_TOOLBAR_BTN_OUTLINE}
            disabled={isRefreshing || hasSearchQuery}
            onClick={() => void refreshList(page)}
          >
            {isRefreshing ? <Loader2 className="size-3.5 animate-spin" /> : <RefreshCw className="size-3.5" />}
            Refresh
          </Button>
        </div>
      </div>

      <p className="text-muted-foreground text-sm">
        Documents you can access. You can view and download only the files listed below.
      </p>

      <ErrorBanner message={listError} />
      <ErrorBanner message={searchError} />

      <section className="rounded-lg border">
        <div className="flex items-center justify-between border-b bg-muted/30 px-3 py-2">
          <h2 className="text-sm font-semibold">Filters</h2>
          <Button type="button" variant="ghost" size="sm" className="h-7 gap-1 px-2 text-xs" onClick={clearFilters}>
            <X className="size-3.5" />
            Clear
          </Button>
        </div>
        <div className="grid gap-3 p-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
          <div className="space-y-1.5">
            <Label className="text-xs">Doc type</Label>
            <Select
              value={filters.docType || "__all__"}
              onValueChange={(value) =>
                setFilters((prev) => ({ ...prev, docType: value === "__all__" ? "" : value }))
              }
            >
              <SelectTrigger className={cn(SETTINGS_INPUT_CLASS, "h-9")}>
                <SelectValue placeholder="All" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="__all__">All</SelectItem>
                {DEEPDEX_DOC_TYPE_OPTIONS.map((option) => (
                  <SelectItem key={option.value} value={option.value}>
                    {option.label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="space-y-1.5">
            <Label className="text-xs">Issuer</Label>
            <Input
              className={cn(SETTINGS_INPUT_CLASS, "h-9")}
              value={filters.issuer}
              onChange={(event) => setFilters((prev) => ({ ...prev, issuer: event.target.value }))}
              placeholder="Issuer"
            />
          </div>
          <div className="space-y-1.5">
            <Label className="text-xs">Name</Label>
            <Input
              className={cn(SETTINGS_INPUT_CLASS, "h-9")}
              value={filters.name}
              onChange={(event) => setFilters((prev) => ({ ...prev, name: event.target.value }))}
              placeholder="Name"
            />
          </div>
          <div className="space-y-1.5">
            <Label className="text-xs">ISIN / Underlying / Ticker</Label>
            <Input
              className={cn(SETTINGS_INPUT_CLASS, "h-9")}
              value={filters.isin}
              onChange={(event) => setFilters((prev) => ({ ...prev, isin: event.target.value }))}
              placeholder="ISIN, Underlying or Ticker"
            />
          </div>
          <div className="space-y-1.5">
            <Label className="text-xs">Product type</Label>
            <Input
              className={cn(SETTINGS_INPUT_CLASS, "h-9")}
              value={filters.productType}
              onChange={(event) =>
                setFilters((prev) => ({ ...prev, productType: event.target.value }))
              }
              placeholder="Product type"
            />
          </div>
          <div className="space-y-1.5">
            <Label className="text-xs">Status</Label>
            <Select
              value={filters.status || "__all__"}
              onValueChange={(value) =>
                setFilters((prev) => ({ ...prev, status: value === "__all__" ? "" : value }))
              }
            >
              <SelectTrigger className={cn(SETTINGS_INPUT_CLASS, "h-9")}>
                <SelectValue placeholder="All" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="__all__">All</SelectItem>
                <SelectItem value="Active">Active</SelectItem>
                <SelectItem value="Expired">Expired</SelectItem>
              </SelectContent>
            </Select>
          </div>
        </div>
      </section>

      <section className="rounded-lg border">
        <div className="border-b bg-muted/30 px-3 py-2">
          <h2 className="flex items-center gap-1.5 text-sm font-semibold">
            <Search className="size-3.5" />
            Search
          </h2>
        </div>
        <div className="p-3">
          <div className="relative">
            <Search className="text-muted-foreground absolute top-1/2 left-3 size-4 -translate-y-1/2" />
            <Input
              className={cn(SETTINGS_INPUT_CLASS, "h-10 pl-9")}
              value={query}
              onChange={(event) => setQuery(event.target.value)}
              placeholder="Type to search…"
              autoComplete="off"
            />
            {isSearching ? (
              <Loader2 className="text-muted-foreground absolute top-1/2 right-3 size-4 -translate-y-1/2 animate-spin" />
            ) : null}
          </div>
        </div>
      </section>

      {hasSearchQuery ? (
        <section className="rounded-lg border">
          <div className="flex items-center justify-between border-b bg-muted/30 px-3 py-2">
            <h2 className="text-sm font-semibold">Results</h2>
            <span className="rounded-full bg-muted px-2 py-0.5 text-xs font-semibold">
              {searchResponse?.count ?? 0}
            </span>
          </div>
          {isSearching && !searchResponse ? (
            <p className="text-muted-foreground p-4 text-sm">Searching…</p>
          ) : searchResponse && searchResponse.results.length > 0 ? (
            <div>
              {searchResponse.results.map((result) => (
                <DeepdexSearchResultItem
                  key={result.id}
                  result={result}
                  settings={settings}
                  resolveViewUrl={resolveViewUrl}
                  onDownloadDocument={onDownloadDocument}
                />
              ))}
            </div>
          ) : (
            <p className="text-muted-foreground p-4 text-center text-sm">
              No documents matched your search.
            </p>
          )}
        </section>
      ) : (
        <section className="rounded-lg border">
          <div className="overflow-x-auto">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead className="w-16">ID</TableHead>
                  <TableHead>Document</TableHead>
                  <TableHead>Version</TableHead>
                  <TableHead>Type</TableHead>
                  <TableHead>Size</TableHead>
                  <TableHead>Uploaded</TableHead>
                  <TableHead className="w-24">View</TableHead>
                  <TableHead className="w-28">Download</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {items.length === 0 ? (
                  <TableRow>
                    <TableCell colSpan={8} className="text-muted-foreground h-24 text-center">
                      No documents available.
                    </TableCell>
                  </TableRow>
                ) : (
                  items.map((doc) => {
                    const token = doc.viewToken || doc.downloadToken;
                    return (
                      <TableRow key={doc.id}>
                        <TableCell className="font-mono text-xs">{doc.id}</TableCell>
                        <TableCell className="max-w-[240px] truncate font-medium">
                          {doc.originalName}
                        </TableCell>
                        <TableCell>{doc.fileVersion || "—"}</TableCell>
                        <TableCell>{getDeepdexDocTypeLabel(doc.docType)}</TableCell>
                        <TableCell>{formatFileSize(doc.fileSize)}</TableCell>
                        <TableCell className="whitespace-nowrap text-xs">{doc.uploadedAt || "—"}</TableCell>
                        <TableCell>
                          {token ? (
                            <Button variant="default" {...TABLE_ROW_ICON_BTN} asChild>
                              <a
                                href={getCustomerDeepdexViewUrl(tenant, token)}
                                target="_blank"
                                rel="noopener noreferrer"
                                title="View"
                              >
                                <Eye className="size-3.5" />
                              </a>
                            </Button>
                          ) : (
                            <Button type="button" variant="default" {...TABLE_ROW_ICON_BTN} disabled>
                              <Eye className="size-3.5" />
                            </Button>
                          )}
                        </TableCell>
                        <TableCell>
                          {token ? (
                            <Button
                              type="button"
                              {...TABLE_TOOLBAR_BTN_OUTLINE}
                              className="h-7 gap-1 px-2 text-xs"
                              disabled={downloadingId === doc.id}
                              onClick={() => void handleRowDownload(doc)}
                            >
                              {downloadingId === doc.id ? (
                                <Loader2 className="size-3.5 animate-spin" />
                              ) : (
                                <Download className="size-3.5" />
                              )}
                              Download
                            </Button>
                          ) : (
                            <Button
                              type="button"
                              {...TABLE_TOOLBAR_BTN_OUTLINE}
                              className="h-7 gap-1 px-2 text-xs"
                              disabled
                            >
                              <Download className="size-3.5" />
                              Download
                            </Button>
                          )}
                        </TableCell>
                      </TableRow>
                    );
                  })
                )}
              </TableBody>
            </Table>
          </div>
          <div className="flex items-center justify-between border-t px-3 py-2 text-xs">
            <span className="text-muted-foreground">
              {totalCount === 0
                ? "No documents"
                : `Page ${page} of ${Math.max(pageCount, 1)} · ${totalCount} document${totalCount === 1 ? "" : "s"}`}
            </span>
            <div className="flex gap-1">
              <Button
                type="button"
                {...TABLE_TOOLBAR_BTN_OUTLINE}
                disabled={page <= 1 || isRefreshing || totalCount === 0}
                onClick={() => void refreshList(page - 1)}
              >
                Previous
              </Button>
              <Button
                type="button"
                {...TABLE_TOOLBAR_BTN_OUTLINE}
                disabled={page >= pageCount || isRefreshing || totalCount === 0 || pageCount <= 1}
                onClick={() => void refreshList(page + 1)}
              >
                Next
              </Button>
            </div>
          </div>
        </section>
      )}
    </div>
  );
}
