import { useState, useEffect, useRef } from "react";
import { useQuery } from "@tanstack/react-query";
import { useNavigate, Link as RouterLink } from "react-router-dom";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import IconButton from "@mui/material/IconButton";
import CircularProgress from "@mui/material/CircularProgress";
import { useAlert } from "../context/AlertContext";
import { useAuth } from "../context/AuthContext";
import Forbidden from "../components/Forbidden";
import {
  formatCurrency,
  formatDate,
  formatMultiCurrency,
  czechPlural,
} from "../utils/formatters";
import useTableSort from "../hooks/useTableSort";
import useDebounce from "../hooks/useDebounce";
import { usePaginatedQuery } from "../hooks/usePaginatedQuery";
import { useApiMutation } from "../lib/queries/mutations";
import { useDocumentListPdf } from "../hooks/useDocumentPdf";
import {
  issuedOrderListOptions,
  issuedOrderStatsOptions,
  issuedOrderSuppliersOptions,
  type IssuedOrder,
} from "../lib/queries/issued-orders";
import {
  Button,
  Card,
  DataTable,
  Pagination,
  ConfirmDialog,
  TextField,
  Select,
  StatusChip,
  FilterBar,
  EmptyState,
  LoadingState,
  type DataColumn,
} from "../ui";
import {
  ISSUED_ORDER_STATUS,
  statusLabel,
  statusColor,
  statusOptions,
  documentNumberLabel,
} from "../lib/documentStatus";

const API_BASE = "/api/admin";

// DELIBERATE deviation from the Offers status-Tabs row: this page is embedded
// under the parent Orders page, which already renders the identical centered
// kit <Tabs> (Vydané/Přijaté) directly above this component — a second
// same-styled tab row would visually fight it (and the sibling "Přijaté" tab
// filters via a Select too). So the status filter stays a Select, with the
// "all" entry relabeled to match the offers tabs ("Všechny").
const STATUS_OPTIONS = statusOptions(ISSUED_ORDER_STATUS, {
  value: "",
  label: "Všechny",
});

const ViewIcon = (
  <svg
    width="18"
    height="18"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
  >
    <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
    <circle cx="12" cy="12" r="3" />
  </svg>
);
const EditIcon = (
  <svg
    width="18"
    height="18"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
  >
    <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
    <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
  </svg>
);
const PdfIcon = (
  <svg
    width="18"
    height="18"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
  >
    <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
    <polyline points="14 2 14 8 20 8" />
    <line x1="16" y1="13" x2="8" y2="13" />
    <line x1="16" y1="17" x2="8" y2="17" />
  </svg>
);
const DeleteIcon = (
  <svg
    width="18"
    height="18"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    strokeLinejoin="round"
  >
    <polyline points="3 6 5 6 21 6" />
    <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
  </svg>
);

interface IssuedOrdersProps {
  month: number;
  year: number;
}

export default function IssuedOrders({ month, year }: IssuedOrdersProps) {
  const alert = useAlert();
  const { hasPermission } = useAuth();
  const navigate = useNavigate();

  const { sort, order, handleSort } = useTableSort("po_number");
  const [search, setSearch] = useState("");
  const debouncedSearch = useDebounce(search, 300);
  const [status, setStatus] = useState("");
  const [supplierFilter, setSupplierFilter] = useState<number | "">("");
  const [page, setPage] = useState(1);
  // Track first successful load so later refetches (filter/status/page change)
  // keep the table visible instead of flashing the full-page skeleton.
  const hasLoadedOnce = useRef(false);

  const { data: suppliers } = useQuery(issuedOrderSuppliersOptions());

  // Shared hardened PDF flow (per-row spinner, double-click guard, 401 silent
  // close, blob-URL revoke + unmount cleanup) — same hook as the Offers list.
  const { openPdf, pdfLoadingId } = useDocumentListPdf();

  const [deleteConfirm, setDeleteConfirm] = useState<{
    show: boolean;
    order: IssuedOrder | null;
  }>({ show: false, order: null });

  const deleteMutation = useApiMutation<
    { id: number },
    { message?: string; error?: string }
  >({
    url: ({ id }) => `${API_BASE}/issued-orders/${id}`,
    method: () => "DELETE",
    invalidate: ["issued-orders"],
    onSuccess: (data) => {
      setDeleteConfirm({ show: false, order: null });
      alert.success(data?.message || "Objednávka byla smazána");
    },
  });

  const {
    items: orders,
    pagination,
    isPending,
    isFetching,
  } = usePaginatedQuery<IssuedOrder>(
    issuedOrderListOptions({
      search: debouncedSearch,
      sort,
      order,
      page,
      status: status || undefined,
      supplier_id: supplierFilter || undefined,
      month,
      year,
    }),
  );

  // Per-currency total over the WHOLE filtered set (not one page). Uses the
  // SAME filters as the list query so the summary matches what's shown.
  const statsQuery = useQuery(
    issuedOrderStatsOptions({
      search: debouncedSearch,
      status: status || undefined,
      supplier_id: supplierFilter || undefined,
      month,
      year,
    }),
  );

  // Mark first load done in an effect (not during render) to avoid a
  // render-phase ref mutation.
  useEffect(() => {
    if (!isPending) hasLoadedOnce.current = true;
  }, [isPending]);

  if (!hasPermission("orders.view")) return <Forbidden />;

  const handleDelete = async () => {
    if (!deleteConfirm.order) return;
    try {
      await deleteMutation.mutateAsync({ id: deleteConfirm.order.id });
    } catch (e) {
      alert.error(e instanceof Error ? e.message : "Chyba připojení");
    }
  };

  // Only show the full-page skeleton on the very first load; on subsequent
  // refetches (filter/status/page change) keep the table visible (the Card
  // dims via isFetching) so it doesn't flash.
  if (isPending && !hasLoadedOnce.current) {
    return <LoadingState />;
  }

  const columns: DataColumn<IssuedOrder>[] = [
    {
      key: "po_number",
      header: "Číslo",
      width: "16%",
      sortKey: "po_number",
      mono: true,
      render: (o) => (
        <Box
          component={RouterLink}
          to={`/orders/issued/${o.id}`}
          sx={{
            color: "primary.main",
            textDecoration: "none",
            "&:hover": { textDecoration: "underline" },
          }}
        >
          {documentNumberLabel(o.po_number)}
        </Box>
      ),
    },
    {
      key: "supplier_name",
      header: "Dodavatel",
      width: "24%",
      render: (o) => o.supplier_name || "—",
    },
    {
      key: "order_date",
      header: "Datum",
      width: "13%",
      sortKey: "order_date",
      mono: true,
      render: (o) => (o.order_date ? formatDate(o.order_date) : "—"),
    },
    {
      key: "status",
      header: "Stav",
      width: "14%",
      sortKey: "status",
      render: (o) => (
        <StatusChip
          label={statusLabel(ISSUED_ORDER_STATUS, o.status)}
          color={statusColor(ISSUED_ORDER_STATUS, o.status)}
        />
      ),
    },
    {
      key: "total",
      header: "Celkem",
      width: "14%",
      align: "right",
      mono: true,
      bold: true,
      render: (o) => formatCurrency(o.total, o.currency ?? "CZK"),
    },
    {
      key: "actions",
      header: "Akce",
      width: "14%",
      align: "right",
      render: (o) => {
        // Offers' semantics: read-only rows (completed/cancelled) get the
        // view icon, editable rows get the edit icon.
        const readOnly = o.status === "completed" || o.status === "cancelled";
        return (
          <Box sx={{ display: "flex", gap: 0.5, justifyContent: "flex-end" }}>
            <IconButton
              size="small"
              onClick={() => navigate(`/orders/issued/${o.id}`)}
              aria-label={readOnly ? "Zobrazit" : "Upravit"}
              title={readOnly ? "Zobrazit" : "Upravit"}
            >
              {readOnly ? ViewIcon : EditIcon}
            </IconButton>
            {/* Drafts have no number yet — /file 404s for them. */}
            {hasPermission("orders.view") && o.po_number && (
              <IconButton
                size="small"
                onClick={() =>
                  openPdf(o.id, `${API_BASE}/issued-orders/${o.id}/file`)
                }
                aria-label="Zobrazit objednávku"
                title="Zobrazit objednávku"
                disabled={pdfLoadingId === o.id}
              >
                {pdfLoadingId === o.id ? (
                  <CircularProgress size={16} />
                ) : (
                  PdfIcon
                )}
              </IconButton>
            )}
            {hasPermission("orders.delete") && (
              <IconButton
                size="small"
                color="error"
                onClick={() => setDeleteConfirm({ show: true, order: o })}
                aria-label="Smazat"
                title="Smazat"
              >
                {DeleteIcon}
              </IconButton>
            )}
          </Box>
        );
      },
    },
  ];

  // Per-status row tints — subtle channel-alpha washes (never a solid `.light`
  // fill, which is invisible-text in dark mode). Completed = success wash,
  // cancelled = faded/muted, matching the Offers/Invoices intensity.
  const rowSx = (o: IssuedOrder) => {
    if (o.status === "cancelled") {
      return {
        opacity: 0.6,
        "& td": { color: "var(--mui-palette-text-secondary)" },
      };
    }
    if (o.status === "completed") {
      return {
        backgroundColor: "rgba(var(--mui-palette-success-mainChannel) / 0.12)",
        "&:hover": {
          backgroundColor:
            "rgba(var(--mui-palette-success-mainChannel) / 0.18)",
        },
      };
    }
    return {};
  };

  // Search/status/supplier filter is active → an empty list means "nothing
  // matches" (no create CTA); a genuinely empty list keeps the create-CTA
  // empty state.
  const isFiltered = !!debouncedSearch || !!status || !!supplierFilter;

  const total = pagination?.total ?? orders.length;
  const countLine = `${total} ${czechPlural(
    total,
    "objednávka",
    "objednávky",
    "objednávek",
  )}`;

  return (
    <>
      <Typography variant="body2" color="text.secondary" sx={{ mb: 1.5 }}>
        {countLine}
      </Typography>

      <FilterBar>
        <Box sx={{ flex: "1 1 320px" }}>
          <TextField
            value={search}
            onChange={(e) => {
              setSearch(e.target.value);
              setPage(1);
            }}
            placeholder="Hledat podle čísla nebo dodavatele..."
            fullWidth
          />
        </Box>
        <Box sx={{ flex: "0 1 200px" }}>
          <Select
            value={status}
            onChange={(value) => {
              setStatus(value);
              setPage(1);
            }}
            options={STATUS_OPTIONS}
          />
        </Box>
        <Box sx={{ flex: "0 0 220px" }}>
          <Select
            value={supplierFilter === "" ? "" : String(supplierFilter)}
            onChange={(value) => {
              setSupplierFilter(value ? Number(value) : "");
              setPage(1);
            }}
            options={[
              { value: "", label: "Všichni dodavatelé" },
              ...(suppliers ?? []).map((s) => ({
                value: String(s.id),
                label: s.name,
              })),
            ]}
          />
        </Box>
      </FilterBar>

      <Card sx={{ opacity: isFetching ? 0.6 : 1, transition: "opacity .2s" }}>
        <DataTable<IssuedOrder>
          columns={columns}
          rows={orders}
          rowKey={(o) => o.id}
          rowSx={rowSx}
          sortBy={sort}
          sortDir={order}
          onSort={handleSort}
          empty={
            isFiltered ? (
              <EmptyState
                title="Žádné objednávky neodpovídají filtru"
                description="Zkuste změnit filtr nebo hledaný výraz."
              />
            ) : (
              <EmptyState
                title="Zatím žádné vydané objednávky."
                action={
                  hasPermission("orders.create") ? (
                    <Button component={RouterLink} to="/orders/issued/new">
                      Vytvořit objednávku
                    </Button>
                  ) : undefined
                }
              />
            )
          }
        />
        {(statsQuery.data?.length ?? 0) > 0 && (
          <Box
            sx={{
              display: "flex",
              justifyContent: "flex-end",
              mt: 1.5,
              px: 1,
              gap: 1,
              color: "text.secondary",
              fontSize: "0.9rem",
            }}
          >
            <span>Celkem bez DPH:</span>
            <Box
              component="span"
              sx={{ fontWeight: 700, color: "text.primary" }}
            >
              {formatMultiCurrency(statsQuery.data ?? [])}
            </Box>
          </Box>
        )}
        <Pagination
          page={page}
          pageCount={pagination?.total_pages ?? 1}
          onChange={setPage}
        />
      </Card>

      <ConfirmDialog
        isOpen={deleteConfirm.show}
        onClose={() => setDeleteConfirm({ show: false, order: null })}
        onConfirm={handleDelete}
        title="Smazat objednávku"
        message={
          deleteConfirm.order
            ? `Opravdu chcete smazat objednávku „${documentNumberLabel(deleteConfirm.order.po_number)}“? Budou smazány i všechny položky. Tato akce je nevratná.`
            : ""
        }
        confirmText="Smazat"
        confirmVariant="danger"
        loading={deleteMutation.isPending}
      />
    </>
  );
}
