import { SortingState } from '@tanstack/react-table';
import { AlertTriangle, Globe } from 'lucide-react';
import { toast } from 'sonner';

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';

import { router, usePage } from '@inertiajs/react';

import AdminPage from '@/Components/admin/AdminPage';
import { AdminSearchInput } from '@/Components/admin/AdminSearchInput';
import { AdminStatsGrid } from '@/Components/admin/AdminStatsGrid';
import type { StatCard } from '@/Components/admin/AdminStatsGrid';
import { PerPageSelector } from '@/Components/admin/PerPageSelector';
import { Button } from '@/Components/ui/button';
import { ConfirmDialog } from '@/Components/ui/confirm-dialog';
import { DataTable } from '@/Components/ui/data-table';
import { ExportButton } from '@/Components/ui/export-button';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/Components/ui/select';
import { useAdminFilters } from '@/hooks/useAdminFilters';
import { useAdminKeyboardShortcuts } from '@/hooks/useAdminKeyboardShortcuts';
import { useMutationButton } from '@/hooks/useMutationButton';
import AdminLayout from '@/Layouts/AdminLayout';
import { bulkActionFailed } from '@/lib/adminToasts';
import { bulkPreviewLine } from '@/lib/bulkPreview';
import type { PageProps } from '@/types';
import type { AdminSitesIndexProps } from '@/types/admin';

import { adminSitesColumns } from './Index.columns';

export default function AdminSitesIndex({ sites, filters, stats }: AdminSitesIndexProps) {
  const { search, setSearch, isPending, updateFilter, handleSort, handlePage, clearFilters } =
    useAdminFilters({
      route: '/admin/sites',
      filters,
    });
  const searchInputRef = useRef<HTMLInputElement>(null);
  const { flash } = usePage<PageProps>().props;

  // R7FE-002: admin-selection stays on raw Set<number> (admin-only surface, no cross-page requirement)
  const [selectedIds, setSelectedIds] = useState<Set<number>>(new Set());
  const [bulkConfirmOpen, setBulkConfirmOpen] = useState(false);
  // F5ADMINUX-010: when true, bulk-deactivate sends active filters instead of explicit IDs
  const [selectAllMatching, setSelectAllMatching] = useState(false);

  // Server-side sort state — seeded from current filter params so sort indicators are
  // correct on first render (e.g. when navigating back to a sorted page).
  const [sorting, setSorting] = useState<SortingState>(() =>
    filters.sort ? [{ id: filters.sort, desc: filters.dir === 'desc' }] : [],
  );

  // F5ADMINUX-009: when the backend flashes bulk_deactivated_site_ids (after a bulk-deactivate),
  // show a success toast with a 10-second Undo action button that calls the bulk-restore endpoint.
  useEffect(() => {
    const ids = flash?.bulk_deactivated_site_ids;
    if (!ids || ids.length === 0) return;

    const count = ids.length;
    toast.success(`${count} site(s) deactivated.`, {
      duration: 10000,
      action: {
        label: 'Undo',
        onClick: () => {
          router.post(
            route('admin.sites.bulk-restore'),
            { site_ids: ids },
            {
              preserveScroll: true,
              onError: () => {
                import('sonner').then(({ toast: t }) => {
                  t.error('Undo failed. Some sites could not be restored.');
                });
              },
            },
          );
        },
      },
    });
  }, [flash?.bulk_deactivated_site_ids]);

  const hasFilters = !!(
    filters.search ||
    filters.health ||
    filters.has_gsc ||
    filters.has_wp ||
    filters.trashed
  );

  const currentPage = sites.current_page;
  const lastPage = sites.last_page;
  useAdminKeyboardShortcuts({
    onSearch: () => searchInputRef.current?.focus(),
    onNextPage: currentPage < lastPage ? () => handlePage(currentPage + 1) : undefined,
    onPrevPage: currentPage > 1 ? () => handlePage(currentPage - 1) : undefined,
  });

  const selectableIds = useMemo(
    () => new Set(sites.data.filter((s) => !s.deleted_at).map((s) => s.id)),
    [sites.data],
  );
  const allSelectableSelected =
    selectableIds.size > 0 && [...selectableIds].every((id) => selectedIds.has(id));
  // F5ADMINUX-010: escalation banner shows when full page is selected and there are more matches
  const hasMorePages = sites.total > sites.data.length;

  const bulkPreviewLabels = useMemo(
    () => sites.data.filter((s) => selectedIds.has(s.id)).map((s) => s.domain),
    [sites.data, selectedIds],
  );

  const toggleSite = useCallback((id: number) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }, []);

  const toggleAll = useCallback(() => {
    if (allSelectableSelected) {
      setSelectedIds(new Set());
      setSelectAllMatching(false);
    } else {
      setSelectedIds(new Set(selectableIds));
      setSelectAllMatching(false);
    }
  }, [allSelectableSelected, selectableIds]);

  const bulkDeactivateResolveRef = useRef<(() => void) | null>(null);
  const bulkDeactivateRejectRef = useRef<(() => void) | null>(null);
  const bulkDeactivatePayloadRef = useRef<Parameters<typeof router.post>[1]>({});

  const { processing: isBulkDeactivating, onClick: triggerBulkDeactivate } = useMutationButton(
    (opts) => router.post(route('admin.sites.bulk-deactivate'), bulkDeactivatePayloadRef.current, {
      preserveState: true,
      ...opts,
      onSuccess: () => {
        setSelectedIds(new Set());
        setSelectAllMatching(false);
        setBulkConfirmOpen(false);
        // F5ADMINUX-009: success toast with undo is shown by the
        // flash.bulk_deactivated_site_ids useEffect above.
        bulkDeactivateResolveRef.current?.();
        opts.onFinish?.();
      },
      onError: (errors) => {
        const displayCount = selectAllMatching ? sites.total : selectedIds.size;
        toast.error(bulkActionFailed('deactivate', displayCount, 'sites'));
        bulkDeactivateRejectRef.current?.();
        opts.onError?.(errors);
      },
    }),
  );

  const executeBulkDeactivate = useCallback((): Promise<void> => {
    // F5ADMINUX-010: send filter scope when operator selected all matching;
    // otherwise send explicit IDs from the current page selection.
    const payload = selectAllMatching
      ? { select_all_matching: true, filters }
      : { site_ids: Array.from(selectedIds) };

    if (!selectAllMatching && selectedIds.size === 0) return Promise.resolve();

    bulkDeactivatePayloadRef.current = payload;

    return new Promise((resolve, reject) => {
      bulkDeactivateResolveRef.current = resolve;
      bulkDeactivateRejectRef.current = reject;
      triggerBulkDeactivate();
    });
  }, [selectedIds, selectAllMatching, filters, triggerBulkDeactivate]);

  const columns = useMemo(
    () =>
      adminSitesColumns({
        selectedIds,
        selectableIds,
        allSelectableSelected,
        onToggle: toggleSite,
        onToggleAll: toggleAll,
      }),
    // eslint-disable-next-line react-hooks/exhaustive-deps -- Set identity changes on every render; derive membership from size + contents
    [selectedIds.size, selectableIds.size, allSelectableSelected, toggleSite, toggleAll],
  );

  const statCards: StatCard[] = [
    { title: 'Total Sites', value: stats.total_sites, icon: Globe },
    {
      title: 'Avg Health Score',
      value: stats.avg_health_score,
      format: (n: number) => n.toFixed(1),
    },
    {
      title: 'Both Connections',
      value: stats.both_connections_pct,
      format: (n: number) => `${n.toFixed(1)}%`,
    },
    {
      title: 'Critical Sites',
      value: stats.critical_count,
      icon: AlertTriangle,
      valueClassName: stats.critical_count > 0 ? 'text-destructive' : '',
    },
  ];

  return (
    <AdminLayout>
      <AdminPage
        title="Sites"
        subtitle="Monitor site health across all users"
        breadcrumbs={[{ label: 'Admin', href: '/admin' }, { label: 'Sites' }]}
        actions={<ExportButton href={route('admin.sites.export')} />}
      >
        <AdminStatsGrid stats={statCards} />

        {/* Filters */}
        <fieldset className="flex flex-col sm:flex-row gap-3">
          <legend className="sr-only">Site Filters</legend>
          <AdminSearchInput
            ref={searchInputRef}
            placeholder="Search by site name, domain, or user email..."
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            className="max-w-sm"
            aria-label="Search sites"
            isPending={isPending}
          />
          <Select
            value={filters.health ?? 'all'}
            onValueChange={(value) =>
              updateFilter({ health: value === 'all' ? undefined : value })
            }
          >
            <SelectTrigger className="w-[180px]" aria-label="Filter by health status">
              <SelectValue placeholder="Health: All" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">Health: All</SelectItem>
              <SelectItem value="critical">Critical (&lt;30)</SelectItem>
              <SelectItem value="warning">Warning (30-60)</SelectItem>
            </SelectContent>
          </Select>
          <Select
            value={filters.has_gsc ?? 'all'}
            onValueChange={(value) =>
              updateFilter({ has_gsc: value === 'all' ? undefined : value })
            }
          >
            <SelectTrigger className="w-[170px]" aria-label="Filter by GSC connection">
              <SelectValue placeholder="GSC: All" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">GSC: All</SelectItem>
              <SelectItem value="1">GSC Connected</SelectItem>
              <SelectItem value="0">GSC Not Connected</SelectItem>
            </SelectContent>
          </Select>
          <Select
            value={filters.has_wp ?? 'all'}
            onValueChange={(value) =>
              updateFilter({ has_wp: value === 'all' ? undefined : value })
            }
          >
            <SelectTrigger className="w-[170px]" aria-label="Filter by WP connection">
              <SelectValue placeholder="WP: All" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">WP: All</SelectItem>
              <SelectItem value="1">WP Connected</SelectItem>
              <SelectItem value="0">WP Not Connected</SelectItem>
            </SelectContent>
          </Select>
          <Select
            value={filters.trashed ?? 'all'}
            onValueChange={(value) =>
              updateFilter({ trashed: value === 'all' ? undefined : value })
            }
          >
            <SelectTrigger className="w-[170px]" aria-label="Filter by status">
              <SelectValue placeholder="Status: Active" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">Active Only</SelectItem>
              <SelectItem value="with">All (incl. deleted)</SelectItem>
              <SelectItem value="only">Deleted Only</SelectItem>
            </SelectContent>
          </Select>
          {hasFilters && (
            <Button variant="ghost" size="sm" onClick={clearFilters}>
              Clear filters
            </Button>
          )}
          <div className="sm:ml-auto">
            <PerPageSelector
              value={filters.per_page ?? 25}
              onChange={(perPage) => updateFilter({ per_page: perPage })}
            />
          </div>
        </fieldset>

        {/* Bulk Action Bar */}
        {selectedIds.size > 0 && (
          <div
            className="flex items-center gap-3 rounded-lg border bg-muted/50 px-4 py-2"
            role="status"
            aria-live="polite"
          >
            <span className="text-sm font-medium">
              {selectAllMatching
                ? `All ${sites.total} matching sites selected`
                : `${selectedIds.size} ${selectedIds.size === 1 ? 'site' : 'sites'} selected`}
            </span>
            <Button variant="destructive" size="sm" onClick={() => setBulkConfirmOpen(true)} disabled={isBulkDeactivating}>
              Deactivate ({selectAllMatching ? sites.total : selectedIds.size})
            </Button>
            <Button
              variant="ghost"
              size="sm"
              onClick={() => {
                setSelectedIds(new Set());
                setSelectAllMatching(false);
              }}
              aria-label="Clear selection"
            >
              Clear
            </Button>
          </div>
        )}

        {/* F5ADMINUX-010: escalation banner — shown when all on-page rows are selected and there are more matches */}
        {allSelectableSelected && hasMorePages && !selectAllMatching && (
          <div
            className="rounded-lg border border-info bg-info/10 px-4 py-2 text-sm"
            role="status"
          >
            All {selectableIds.size} sites on this page are selected.{' '}
            <button
              type="button"
              className="font-semibold underline hover:no-underline"
              onClick={() => setSelectAllMatching(true)}
            >
              Select all {sites.total} matching this filter
            </button>
          </div>
        )}

        {selectAllMatching && (
          <div
            className="rounded-lg border border-warning bg-warning/10 px-4 py-2 text-sm text-warning-strong"
            role="status"
          >
            All {sites.total} matching sites will be affected.{' '}
            <button
              type="button"
              className="font-semibold underline hover:no-underline"
              onClick={() => setSelectAllMatching(false)}
            >
              Revert to page selection
            </button>
          </div>
        )}

        {/* R8FE-005: use controlled pageIndex instead of key= remount hack. */}
        <DataTable
          columns={columns}
          data={sites.data}
          manualPagination
          pageCount={sites.last_page}
          pageSize={filters.per_page ?? 25}
          pageIndex={sites.current_page - 1}
          onPaginationChange={(pagination) => {
            handlePage(pagination.pageIndex + 1);
          }}
          sorting={sorting}
          onSortingChange={(updater) => {
            const next = typeof updater === 'function' ? updater(sorting) : updater;
            if (next.length > 0) {
              setSorting(next);
              handleSort(next[0].id);
            }
            // next.length === 0 means TanStack wants to clear sort (third click).
            // Since the original SortHeader had no "clear sort" path, we ignore
            // the clear — keep local state at current sorting so the UI stays in sync
            // with the URL (which still has sort params from the last handleSort call).
          }}
          caption="Sites table"
          emptyState={{
            icon: Globe,
            title: hasFilters ? 'No sites match your filters' : 'No sites in the system yet',
            description: hasFilters
              ? undefined
              : 'Sites appear when users connect their first domain.',
            action: hasFilters ? (
              <Button variant="outline" size="sm" onClick={clearFilters}>
                Clear filters
              </Button>
            ) : undefined,
          }}
        />

        <ConfirmDialog
          open={bulkConfirmOpen}
          onOpenChange={setBulkConfirmOpen}
          onConfirm={executeBulkDeactivate}
          title={`Deactivate ${selectAllMatching ? sites.total : selectedIds.size} site(s)`}
          description={
            <>
              <span>
                Deactivating {selectAllMatching ? sites.total : selectedIds.size} site(s) will
                remove them from those users&apos; dashboards immediately.
              </span>
              {selectAllMatching && (
                <span className="mt-2 block font-medium text-xs text-destructive">
                  All {sites.total} matching sites will be deactivated — not just this page.
                </span>
              )}
              {!selectAllMatching && bulkPreviewLabels.length > 0 && (
                <span className="mt-2 block text-xs text-muted-foreground">
                  About to deactivate: {bulkPreviewLine(bulkPreviewLabels, selectedIds.size)}.
                </span>
              )}
            </>
          }
          variant="destructive"
          confirmLabel="Deactivate"
        />
      </AdminPage>
    </AdminLayout>
  );
}
