import { useState } from "react";
import {
  Text,
  Button,
  Group,
  Skeleton,
  Stack,
  Alert,
  ActionIcon,
  Menu,
} from "@mantine/core";
import {
  IconAlertCircle,
  IconChevronLeft,
  IconChevronRight,
  IconPlus,
  IconDots,
  IconPencil,
  IconTrash,
} from "@tabler/icons-react";
import { useTranslation } from "react-i18next";
import { modals } from "@mantine/modals";
import { useQueryClient } from "@tanstack/react-query";
import { useViewData } from "../hooks/use-view-data";
import { useUpdateRow } from "../hooks/use-update-row";
import { useDatabaseRealtimeUpdates } from "../hooks/use-database-realtime-updates";
import { usePermissions } from "../hooks/use-permissions";
import { useAcadenicePermissions } from "@/features/acadenice/rbac/hooks/use-acadenice-permissions";
import { InlineEditor } from "../components/inline-editor";
import { FieldAdminModal } from "../components/field-admin-modal";
import { deleteField } from "../services/admin-client";
import type { BridgeField, BridgeRow } from "../types/database-view.types";
import styles from "./table-renderer.module.css";

/**
 * NOTE: This renderer uses plain HTML table elements.
 *
 * TanStack Table v8 (@tanstack/react-table) is NOT yet installed in
 * apps/client/package.json. The headless table logic here is a faithful
 * placeholder that mirrors the TanStack Table v8 mental model (columns derived
 * from BridgeField[], rows from BridgeRow[]) so migration is a drop-in.
 *
 * To migrate: install @tanstack/react-table@^8, then replace the manual
 * column/row loops with useReactTable() + flexRender(). The data shape
 * (fields + rows) is already correct.
 *
 * DEPENDENCY NEEDED: @tanstack/react-table@^8
 */

const PAGE_SIZE = 50;

interface TableRendererProps {
  tableId: string;
  viewId: string;
  bridgeUrl?: string | null;
}

interface EditingCell {
  rowId: string;
  fieldId: string;
}

/** Display format for a raw cell value — keeps the table readable without edit. */
function formatCellValue(value: unknown): string {
  if (value === null || value === undefined) return "";
  if (typeof value === "boolean") return value ? "true" : "false";
  if (typeof value === "object") {
    // Arrays of strings/objects (select, link fields in Baserow)
    if (Array.isArray(value)) {
      return value
        .map((v) => (typeof v === "object" && v !== null ? (v as { value?: string }).value ?? JSON.stringify(v) : String(v)))
        .join(", ");
    }
    // Objects (file fields, etc.)
    return (value as { value?: string }).value ?? JSON.stringify(value);
  }
  return String(value);
}

/** Loading skeleton mimicking the table layout. */
function TableSkeleton() {
  return (
    <div className={styles.skeleton}>
      {Array.from({ length: 5 }).map((_, i) => (
        <div key={i} className={styles.skeletonRow}>
          <Skeleton height={18} width="20%" />
          <Skeleton height={18} width="30%" />
          <Skeleton height={18} width="25%" />
          <Skeleton height={18} width="15%" />
        </div>
      ))}
    </div>
  );
}

interface TableBodyProps {
  fields: BridgeField[];
  rows: BridgeRow[];
  editingCell: EditingCell | null;
  canWrite: boolean;
  onCellDoubleClick: (rowId: string, fieldId: string) => void;
  onCellSave: (rowId: string, field: BridgeField, value: unknown) => void;
  onCellCancel: () => void;
}

function TableBody({
  fields,
  rows,
  editingCell,
  canWrite,
  onCellDoubleClick,
  onCellSave,
  onCellCancel,
}: TableBodyProps) {
  const { t } = useTranslation();

  if (rows.length === 0) {
    return (
      <tr>
        <td colSpan={fields.length} className={styles.emptyState}>
          <Text size="sm" c="dimmed">
            {t("database_view.table.empty_state")}
          </Text>
        </td>
      </tr>
    );
  }

  return (
    <>
      {rows.map((row) => (
        <tr key={row.id} className={styles.tr}>
          {fields.map((field) => {
            const isEditing =
              editingCell?.rowId === row.id && editingCell?.fieldId === field.id;
            const cellValue = row.fields[field.name] ?? row.fields[field.id];

            return (
              <td
                key={field.id}
                className={styles.td}
                data-testid={`cell-${row.id}-${field.name}`}
                onDoubleClick={() => {
                  if (!isEditing) {
                    onCellDoubleClick(row.id, field.id);
                  }
                }}
              >
                {isEditing ? (
                  <InlineEditor
                    field={field}
                    initialValue={cellValue}
                    canWrite={canWrite}
                    onSave={(v) => onCellSave(row.id, field, v)}
                    onCancel={onCellCancel}
                  />
                ) : (
                  formatCellValue(cellValue)
                )}
              </td>
            );
          })}
        </tr>
      ))}
    </>
  );
}

export function TableRenderer({ tableId, viewId, bridgeUrl }: TableRendererProps) {
  const { t } = useTranslation();
  const [page, setPage] = useState(1);
  const [editingCell, setEditingCell] = useState<EditingCell | null>(null);

  const { data, isLoading, isError, error, refetch } = useViewData({
    viewId,
    tableId,
    bridgeUrl,
    page,
    size: PAGE_SIZE,
  });

  const { canWriteRows } = usePermissions();
  // Acadenice OSS: tout user (role Member par defaut) a tables:write.
  // Le gate reste pour les roles custom restrictifs.
  const acadenicePerms = useAcadenicePermissions();
  const canAdminTables = acadenicePerms.hasPermission("tables:write");
  const queryClient = useQueryClient();
  const updateRow = useUpdateRow({ tableId, viewId, bridgeUrl });

  // Field admin modal state.
  const [fieldModalOpen, setFieldModalOpen] = useState(false);
  const [editingField, setEditingField] = useState<BridgeField | null>(null);

  function openCreateField() {
    setEditingField(null);
    setFieldModalOpen(true);
  }

  function openEditField(field: BridgeField) {
    setEditingField(field);
    setFieldModalOpen(true);
  }

  function refreshAfterFieldChange() {
    // Invalidate the view-data cache so the table re-renders with new fields.
    queryClient.invalidateQueries({ queryKey: ["database-view", viewId] });
    queryClient.invalidateQueries({ queryKey: ["database-view"] });
  }

  function confirmDeleteField(field: BridgeField) {
    modals.openConfirmModal({
      title: "Supprimer la colonne",
      children: (
        <Text size="sm">
          La colonne <strong>{field.name}</strong> et toutes ses valeurs seront
          définitivement supprimées. Action irréversible.
        </Text>
      ),
      labels: { confirm: "Supprimer", cancel: "Annuler" },
      confirmProps: { color: "red" },
      onConfirm: async () => {
        try {
          await deleteField(Number(field.id), bridgeUrl);
          refreshAfterFieldChange();
        } catch (e) {
          // best-effort surface — invalidate to refresh UI
          refreshAfterFieldChange();
          // eslint-disable-next-line no-console
          console.error("delete field failed", e);
        }
      },
    });
  }

  // Subscribe to SSE updates — invalidates React Query cache on row/view events.
  useDatabaseRealtimeUpdates(tableId, viewId, bridgeUrl);

  if (isLoading) {
    return <TableSkeleton />;
  }

  if (isError) {
    const axiosError = error as { response?: { status?: number } };
    const status = axiosError?.response?.status;

    let message = t("database_view.error.generic");
    if (status === 403) message = t("database_view.error.permission_denied");
    else if (status === 404) message = t("database_view.error.view_not_found");

    return (
      <Alert
        icon={<IconAlertCircle size={16} />}
        color="red"
        title={t("database_view.error.title")}
      >
        <Stack gap="xs">
          <Text size="sm">{message}</Text>
          <Button size="xs" variant="subtle" onClick={() => refetch()}>
            {t("database_view.error.retry")}
          </Button>
        </Stack>
      </Alert>
    );
  }

  const { rows, fields, total, hasNextPage } = data ?? {
    rows: [],
    fields: [],
    total: 0,
    hasNextPage: false,
  };

  function handleCellSave(rowId: string, field: BridgeField, value: unknown) {
    setEditingCell(null);
    updateRow.mutate({
      rowId,
      payload: { fields: { [field.name]: value } },
    });
  }

  return (
    <div>
      <div className={styles.wrapper}>
        <table className={styles.table} data-testid="table-renderer">
          <thead>
            <tr>
              {fields.map((field) => (
                <th key={field.id} className={styles.th}>
                  <Group gap={4} wrap="nowrap" justify="space-between">
                    <Text size="sm" fw={500} truncate>
                      {field.name}
                    </Text>
                    {canAdminTables && !field.primary && (
                      <Menu shadow="md" width={180} position="bottom-end">
                        <Menu.Target>
                          <ActionIcon
                            size="xs"
                            variant="subtle"
                            aria-label={`Options ${field.name}`}
                          >
                            <IconDots size={14} />
                          </ActionIcon>
                        </Menu.Target>
                        <Menu.Dropdown>
                          <Menu.Item
                            leftSection={<IconPencil size={14} />}
                            onClick={() => openEditField(field)}
                          >
                            Modifier
                          </Menu.Item>
                          <Menu.Item
                            leftSection={<IconTrash size={14} />}
                            color="red"
                            onClick={() => confirmDeleteField(field)}
                          >
                            Supprimer
                          </Menu.Item>
                        </Menu.Dropdown>
                      </Menu>
                    )}
                  </Group>
                </th>
              ))}
              {canAdminTables && (
                <th className={styles.th} style={{ width: 32 }}>
                  <ActionIcon
                    variant="subtle"
                    size="sm"
                    onClick={openCreateField}
                    aria-label="Ajouter une colonne"
                    title="Ajouter une colonne"
                  >
                    <IconPlus size={16} />
                  </ActionIcon>
                </th>
              )}
            </tr>
          </thead>
          <tbody>
            <TableBody
              fields={fields}
              rows={rows}
              editingCell={editingCell}
              canWrite={canWriteRows}
              onCellDoubleClick={(rowId, fieldId) =>
                setEditingCell({ rowId, fieldId })
              }
              onCellSave={handleCellSave}
              onCellCancel={() => setEditingCell(null)}
            />
          </tbody>
        </table>
      </div>

      {/* Pagination — only shown when there is more than one page. */}
      {(page > 1 || hasNextPage) && (
        <div className={styles.pagination}>
          <Text size="xs">
            {t("database_view.table.page_info", {
              page,
              total,
              size: PAGE_SIZE,
            })}
          </Text>
          <Group gap="xs">
            <Button
              size="xs"
              variant="subtle"
              disabled={page === 1}
              leftSection={<IconChevronLeft size={14} />}
              onClick={() => setPage((p) => Math.max(1, p - 1))}
            >
              {t("database_view.table.prev")}
            </Button>
            <Button
              size="xs"
              variant="subtle"
              disabled={!hasNextPage}
              rightSection={<IconChevronRight size={14} />}
              onClick={() => setPage((p) => p + 1)}
            >
              {t("database_view.table.next")}
            </Button>
          </Group>
        </div>
      )}
    </div>
  );
}
