import type { ReactNode } from "react";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import IconButton from "@mui/material/IconButton";
import Checkbox from "@mui/material/Checkbox";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import useMediaQuery from "@mui/material/useMediaQuery";
import { useTheme } from "@mui/material/styles";
import {
  DndContext,
  closestCenter,
  KeyboardSensor,
  PointerSensor,
  TouchSensor,
  useSensor,
  useSensors,
  type DragEndEvent,
} from "@dnd-kit/core";
import {
  SortableContext,
  verticalListSortingStrategy,
  useSortable,
  arrayMove,
} from "@dnd-kit/sortable";
import {
  restrictToVerticalAxis,
  restrictToParentElement,
} from "@dnd-kit/modifiers";
import { CSS } from "@dnd-kit/utilities";
import { Button, Card, TextField } from "../../ui";
import { formatCurrency } from "../../utils/formatters";

/**
 * One sortable line item of a document (offer / issued order). The numeric
 * fields are held as the raw typed string while editing so the input can be
 * cleared (empty renders fine in a type="number" input); coerce via
 * `Number(x) || 0` only where used (live totals + save payload).
 */
export interface DocumentItem {
  _key: string;
  id?: number;
  description: string;
  item_description: string;
  quantity: string | number;
  unit: string;
  unit_price: string | number;
  /** Offers only — undefined (issued orders) counts as included. */
  is_included_in_total?: boolean;
}

let documentItemKeyCounter = 0;

/** Unique client-side key for a (new or hydrated) document item row. */
export const nextDocumentItemKey = (): string =>
  `item-${++documentItemKeyCounter}`;

export const emptyDocumentItem = (): DocumentItem => ({
  _key: nextDocumentItemKey(),
  description: "",
  item_description: "",
  quantity: 1,
  unit: "ks",
  unit_price: 0,
  is_included_in_total: true,
});

/** NET total over the included items (documents here carry no VAT). */
export const documentItemsTotal = (items: DocumentItem[]): number =>
  items.reduce(
    (sum, it) =>
      it.is_included_in_total === false
        ? sum
        : sum + (Number(it.quantity) || 0) * (Number(it.unit_price) || 0),
    0,
  );

const DragIcon = (
  <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
    <circle cx="9" cy="5" r="1.5" />
    <circle cx="15" cy="5" r="1.5" />
    <circle cx="9" cy="12" r="1.5" />
    <circle cx="15" cy="12" r="1.5" />
    <circle cx="9" cy="19" r="1.5" />
    <circle cx="15" cy="19" r="1.5" />
  </svg>
);

const RemoveIcon = (
  <svg
    width="16"
    height="16"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
  >
    <line x1="18" y1="6" x2="6" y2="18" />
    <line x1="6" y1="6" x2="18" y2="18" />
  </svg>
);

function SortableItemRow({
  item,
  index,
  currency,
  readOnly,
  canDelete,
  showIncludedInTotal,
  itemDescriptionMaxLength,
  onUpdate,
  onRemove,
}: {
  item: DocumentItem;
  index: number;
  currency: string;
  readOnly: boolean;
  canDelete: boolean;
  showIncludedInTotal: boolean;
  itemDescriptionMaxLength: number;
  onUpdate: (field: keyof DocumentItem, value: string | boolean) => void;
  onRemove: () => void;
}) {
  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging,
  } = useSortable({ id: item._key, disabled: readOnly });
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.5 : 1,
    background: isDragging ? "var(--mui-palette-action-hover)" : undefined,
    position: "relative" as const,
    zIndex: isDragging ? 10 : undefined,
  };
  const lineTotal =
    (Number(item.quantity) || 0) * (Number(item.unit_price) || 0);

  if (isMobile) {
    return (
      <Box
        ref={setNodeRef}
        sx={{
          border: 1,
          borderColor: "divider",
          borderRadius: 2,
          p: 1.5,
          display: "flex",
          flexDirection: "column",
          gap: 1.25,
          bgcolor: "background.paper",
          ...style,
        }}
      >
        <Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
          {!readOnly && (
            <IconButton
              size="small"
              {...attributes}
              {...listeners}
              title="Přetáhnout"
              aria-label="Přetáhnout"
              sx={{ cursor: "grab", color: "text.secondary" }}
            >
              {DragIcon}
            </IconButton>
          )}
          <Typography
            variant="caption"
            sx={{ color: "text.secondary", fontWeight: 700 }}
          >
            Položka {index + 1}
          </Typography>
          <Box sx={{ flex: 1 }} />
          {!readOnly && (
            <IconButton
              color="error"
              size="small"
              onClick={onRemove}
              title="Odebrat"
              aria-label="Odebrat"
              disabled={!canDelete}
            >
              {RemoveIcon}
            </IconButton>
          )}
        </Box>
        <TextField
          label="Popis"
          value={item.description}
          onChange={(e) => onUpdate("description", e.target.value)}
          placeholder="Popis položky…"
          InputProps={{ readOnly }}
          slotProps={{ htmlInput: { maxLength: 500 } }}
        />
        <TextField
          label="Podrobný popis"
          value={item.item_description}
          onChange={(e) => onUpdate("item_description", e.target.value)}
          placeholder="Volitelný"
          InputProps={{ readOnly }}
          multiline
          rows={2}
          slotProps={{ htmlInput: { maxLength: itemDescriptionMaxLength } }}
          sx={{ "& textarea": { resize: "vertical" } }}
        />
        <Box
          sx={{
            display: "grid",
            gridTemplateColumns: "repeat(3, minmax(0, 1fr))",
            gap: 1,
          }}
        >
          <TextField
            label="Množství"
            type="number"
            value={item.quantity ?? ""}
            onChange={(e) => onUpdate("quantity", e.target.value)}
            slotProps={{ htmlInput: { min: "0", step: "any" } }}
            InputProps={{ readOnly }}
            sx={{ "& input": { textAlign: "center" } }}
          />
          <TextField
            label="Jednotka"
            value={item.unit}
            onChange={(e) => onUpdate("unit", e.target.value)}
            placeholder="ks"
            InputProps={{ readOnly }}
            slotProps={{ htmlInput: { maxLength: 20 } }}
            sx={{ "& input": { textAlign: "center" } }}
          />
          <TextField
            label="Jedn. cena"
            type="number"
            value={item.unit_price ?? ""}
            onChange={(e) => onUpdate("unit_price", e.target.value)}
            slotProps={{ htmlInput: { min: "0", step: "any" } }}
            InputProps={{ readOnly }}
            sx={{ "& input": { textAlign: "right" } }}
          />
        </Box>
        <Box
          sx={{
            display: "flex",
            justifyContent: showIncludedInTotal ? "space-between" : "flex-end",
            alignItems: "baseline",
            gap: 1,
            pt: 0.5,
            borderTop: 1,
            borderColor: "divider",
          }}
        >
          {showIncludedInTotal && (
            <Box
              component="label"
              sx={{
                display: "flex",
                alignItems: "center",
                gap: 0.5,
                cursor: readOnly ? "default" : "pointer",
              }}
            >
              <Checkbox
                checked={item.is_included_in_total !== false}
                onChange={(e) =>
                  onUpdate("is_included_in_total", e.target.checked)
                }
                disabled={readOnly}
              />
              <Typography variant="body2">V ceně</Typography>
            </Box>
          )}
          <Box
            sx={{
              display: "flex",
              alignItems: "baseline",
              gap: 1,
            }}
          >
            <Typography variant="caption" sx={{ color: "text.secondary" }}>
              Celkem
            </Typography>
            <Typography
              sx={{
                fontFamily: "'DM Mono', Menlo, monospace",
                fontWeight: 600,
              }}
            >
              {formatCurrency(lineTotal, currency)}
            </Typography>
          </Box>
        </Box>
      </Box>
    );
  }

  return (
    <TableRow ref={setNodeRef} sx={style}>
      {/* Stable column layout: every cell renders in read-only mode too —
          only the controls inside are hidden. */}
      <TableCell sx={{ width: "2rem", px: 0.5 }}>
        {!readOnly && (
          <IconButton
            size="small"
            {...attributes}
            {...listeners}
            title="Přetáhnout"
            aria-label="Přetáhnout"
            sx={{ cursor: "grab", color: "text.secondary" }}
          >
            {DragIcon}
          </IconButton>
        )}
      </TableCell>
      <TableCell
        align="center"
        sx={{ color: "text.secondary", fontWeight: 500 }}
      >
        {index + 1}
      </TableCell>
      <TableCell sx={{ verticalAlign: "top" }}>
        <Box sx={{ display: "flex", flexDirection: "column", gap: 0.5 }}>
          <TextField
            value={item.description}
            onChange={(e) => onUpdate("description", e.target.value)}
            placeholder="Popis položky…"
            InputProps={{ readOnly }}
            slotProps={{ htmlInput: { maxLength: 500 } }}
            sx={{ "& input": { fontWeight: 500 } }}
          />
          <TextField
            value={item.item_description}
            onChange={(e) => onUpdate("item_description", e.target.value)}
            placeholder="Podrobný popis (volitelný)"
            InputProps={{ readOnly }}
            multiline
            rows={2}
            slotProps={{ htmlInput: { maxLength: itemDescriptionMaxLength } }}
            sx={{
              "& textarea": {
                fontSize: "0.8rem",
                opacity: 0.8,
                resize: "vertical",
              },
            }}
          />
        </Box>
      </TableCell>
      <TableCell>
        <TextField
          type="number"
          value={item.quantity ?? ""}
          onChange={(e) => onUpdate("quantity", e.target.value)}
          slotProps={{ htmlInput: { min: "0", step: "any" } }}
          InputProps={{ readOnly }}
          sx={{ "& input": { textAlign: "center" } }}
        />
      </TableCell>
      <TableCell>
        <TextField
          value={item.unit}
          onChange={(e) => onUpdate("unit", e.target.value)}
          placeholder="ks"
          InputProps={{ readOnly }}
          slotProps={{ htmlInput: { maxLength: 20 } }}
          sx={{ "& input": { textAlign: "center" } }}
        />
      </TableCell>
      <TableCell>
        <TextField
          type="number"
          value={item.unit_price ?? ""}
          onChange={(e) => onUpdate("unit_price", e.target.value)}
          slotProps={{ htmlInput: { min: "0", step: "any" } }}
          InputProps={{ readOnly }}
          sx={{ "& input": { textAlign: "right" } }}
        />
      </TableCell>
      {showIncludedInTotal && (
        <TableCell align="center">
          <Checkbox
            checked={item.is_included_in_total !== false}
            onChange={(e) => onUpdate("is_included_in_total", e.target.checked)}
            disabled={readOnly}
          />
        </TableCell>
      )}
      <TableCell
        align="right"
        sx={{
          fontWeight: 600,
          whiteSpace: "nowrap",
          fontFamily: "'DM Mono', Menlo, monospace",
        }}
      >
        {formatCurrency(lineTotal, currency)}
      </TableCell>
      <TableCell sx={{ width: "2.5rem" }}>
        {!readOnly && (
          <IconButton
            color="error"
            size="small"
            onClick={onRemove}
            title="Odebrat"
            aria-label="Odebrat"
            disabled={!canDelete}
          >
            {RemoveIcon}
          </IconButton>
        )}
      </TableCell>
    </TableRow>
  );
}

interface DocumentItemsEditorProps {
  items: DocumentItem[];
  onChange: (items: DocumentItem[]) => void;
  currency: string;
  readOnly: boolean;
  /** Validation error shown under the section title. */
  error?: string;
  /** Render the offers-only "V ceně" (is_included_in_total) column. */
  showIncludedInTotal?: boolean;
  /** Schema cap for the detailed description (offers 8000, issued orders 5000). */
  itemDescriptionMaxLength?: number;
  /** Optional page-specific control (e.g. item-template Select) next to the add button. */
  templatesSlot?: ReactNode;
}

/**
 * Sortable line-items table shared by the document detail pages (offers,
 * issued orders): drag-and-drop reorder, mobile card layout, live NET totals
 * ("Celkem bez DPH" — these documents are not tax documents).
 */
export default function DocumentItemsEditor({
  items,
  onChange,
  currency,
  readOnly,
  error,
  showIncludedInTotal = false,
  itemDescriptionMaxLength = 5000,
  templatesSlot,
}: DocumentItemsEditorProps) {
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
  const dndSensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
    useSensor(TouchSensor, {
      activationConstraint: { delay: 200, tolerance: 5 },
    }),
    useSensor(KeyboardSensor),
  );

  const updateItem = (
    index: number,
    field: keyof DocumentItem,
    value: string | boolean,
  ) =>
    onChange(
      items.map((it, i) => (i === index ? { ...it, [field]: value } : it)),
    );

  const addItem = () => onChange([...items, emptyDocumentItem()]);

  const removeItem = (index: number) => {
    if (items.length <= 1) return;
    onChange(items.filter((_, i) => i !== index));
  };

  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    if (!over || active.id === over.id) return;
    const oldIndex = items.findIndex((i) => i._key === String(active.id));
    const newIndex = items.findIndex((i) => i._key === String(over.id));
    if (oldIndex === -1 || newIndex === -1) return;
    onChange(arrayMove(items, oldIndex, newIndex));
  };

  const total = documentItemsTotal(items);

  return (
    <Card sx={{ mb: 3 }}>
      <Box
        sx={{
          display: "flex",
          justifyContent: "space-between",
          alignItems: "flex-start",
          mb: 2,
        }}
      >
        <Box>
          <Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
            Položky
          </Typography>
          {error && (
            <Typography variant="caption" color="error">
              {error}
            </Typography>
          )}
        </Box>
        {!readOnly && (
          <Box sx={{ display: "flex", gap: 1, alignItems: "center" }}>
            {templatesSlot}
            <Button
              type="button"
              onClick={addItem}
              variant="outlined"
              color="inherit"
              size="small"
            >
              + Přidat položku
            </Button>
          </Box>
        )}
      </Box>

      <DndContext
        sensors={dndSensors}
        collisionDetection={closestCenter}
        modifiers={[restrictToVerticalAxis, restrictToParentElement]}
        onDragEnd={handleDragEnd}
      >
        <SortableContext
          items={items.map((i) => i._key)}
          strategy={verticalListSortingStrategy}
        >
          {isMobile ? (
            <Box sx={{ display: "flex", flexDirection: "column", gap: 1.5 }}>
              {items.map((item, index) => (
                <SortableItemRow
                  key={item._key}
                  item={item}
                  index={index}
                  currency={currency}
                  readOnly={readOnly}
                  canDelete={items.length > 1}
                  showIncludedInTotal={showIncludedInTotal}
                  itemDescriptionMaxLength={itemDescriptionMaxLength}
                  onUpdate={(field, value) => updateItem(index, field, value)}
                  onRemove={() => removeItem(index)}
                />
              ))}
            </Box>
          ) : (
            <TableContainer sx={{ overflowX: "auto" }}>
              <Table
                size="small"
                sx={{
                  minWidth: 720,
                  "& td, & th": { borderColor: "divider" },
                }}
              >
                <TableHead>
                  <TableRow>
                    <TableCell sx={{ width: "2rem" }} />
                    <TableCell sx={{ width: "2rem" }} align="center">
                      #
                    </TableCell>
                    <TableCell>Popis</TableCell>
                    <TableCell sx={{ width: "7rem" }} align="center">
                      Množství
                    </TableCell>
                    <TableCell sx={{ width: "5.5rem" }} align="center">
                      Jednotka
                    </TableCell>
                    <TableCell sx={{ width: "8rem" }} align="center">
                      Jedn. cena
                    </TableCell>
                    {showIncludedInTotal && (
                      <TableCell sx={{ width: "4rem" }} align="center">
                        V ceně
                      </TableCell>
                    )}
                    <TableCell sx={{ width: "8rem" }} align="right">
                      Celkem
                    </TableCell>
                    <TableCell sx={{ width: "2.5rem" }} />
                  </TableRow>
                </TableHead>
                <TableBody>
                  {items.map((item, index) => (
                    <SortableItemRow
                      key={item._key}
                      item={item}
                      index={index}
                      currency={currency}
                      readOnly={readOnly}
                      canDelete={items.length > 1}
                      showIncludedInTotal={showIncludedInTotal}
                      itemDescriptionMaxLength={itemDescriptionMaxLength}
                      onUpdate={(field, value) =>
                        updateItem(index, field, value)
                      }
                      onRemove={() => removeItem(index)}
                    />
                  ))}
                </TableBody>
              </Table>
            </TableContainer>
          )}
        </SortableContext>
      </DndContext>

      {/* Totals (NET only — offers/issued orders are not tax documents) */}
      <Box
        sx={{
          mt: 2,
          ml: "auto",
          maxWidth: 360,
          display: "flex",
          flexDirection: "column",
          gap: 0.5,
        }}
      >
        <Box
          sx={{
            display: "flex",
            justifyContent: "space-between",
            pt: 0.5,
            mt: 0.5,
            borderTop: 1,
            borderColor: "divider",
          }}
        >
          <Typography variant="body2" sx={{ fontWeight: 700 }}>
            Celkem bez DPH:
          </Typography>
          <Typography
            variant="body2"
            sx={{
              fontFamily: "'DM Mono', Menlo, monospace",
              fontWeight: 700,
            }}
          >
            {formatCurrency(total, currency)}
          </Typography>
        </Box>
      </Box>
    </Card>
  );
}
