import { useMemo, useState } from "react";
import {
  ActionIcon,
  Badge,
  Box,
  Button,
  Card,
  Code,
  Group,
  SimpleGrid,
  Stack,
  Table,
  Tabs,
  Text,
  TextInput,
  ThemeIcon,
} from "@mantine/core";
import {
  ArrowDownToLine,
  ArrowUpFromLine,
  FileUp,
  FolderOpen,
  HardDrive,
  Inbox,
  Layers,
  Paperclip,
  Search,
  Settings,
  TrainFront,
  X,
} from "lucide-react";
import { useQuery } from "@tanstack/react-query";

import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
import { api } from "@/services/api";
import { getMinFiles, type FileUploadSetting } from "@/types/fileUploadSettings";

import ManageFileUploadFieldsDialog from "./ManageFileUploadFieldsDialog";

type DocCategory = "import" | "export" | "intercity" | "other";

function categorize(setting: FileUploadSetting): DocCategory {
  const code = setting.code.toLowerCase();
  if (code.includes("intercity")) return "intercity";
  if (code.includes("export")) return "export";
  if (code.includes("import")) return "import";
  return "other";
}

export default function FileUploadSettingsPage() {
  const [query, setQuery] = useState("");

  const { data, isLoading, isError, error, refetch } = useQuery(
    api.fileUploadSettings.list.queryOptions(),
  );

  const fileUploadSettings = useMemo(
    () => (Array.isArray(data) ? data : []),
    [data],
  );

  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    if (!q) return fileUploadSettings;
    return fileUploadSettings.filter(
      (s) =>
        s.code.toLowerCase().includes(q) ||
        s.label.toLowerCase().includes(q) ||
        (s.description ?? "").toLowerCase().includes(q) ||
        s.fields.some(
          (f) =>
            f.fileKey.toLowerCase().includes(q) ||
            f.fileLabel.toLowerCase().includes(q),
        ),
    );
  }, [fileUploadSettings, query]);

  const byCategory = useMemo(() => {
    const groups: Record<DocCategory, FileUploadSetting[]> = {
      import: [],
      export: [],
      intercity: [],
      other: [],
    };
    for (const s of filtered) groups[categorize(s)].push(s);
    return groups;
  }, [filtered]);

  const totalFields = fileUploadSettings.reduce(
    (sum, s) => sum + s.fields.length,
    0,
  );
  const requiredFields = fileUploadSettings.reduce(
    (sum, s) => sum + s.fields.filter((f) => f.isRequired).length,
    0,
  );
  const multiFields = fileUploadSettings.reduce(
    (sum, s) => sum + s.fields.filter((f) => f.isMultiple).length,
    0,
  );

  const gridStatus = isLoading ? "loading" : isError ? "error" : "success";

  return (
    <PageContainer>
      <PageHeader
        title="File upload settings"
        subtitle="Define the file inputs every form in the platform should render — required/optional, single/multiple, allowed types and size."
      />

      <KpiStrip
        loading={isLoading}
        items={[
          { label: "Settings", value: fileUploadSettings.length, icon: Settings },
          { label: "Total fields", value: totalFields, icon: Paperclip },
          { label: "Required", value: requiredFields, icon: FileUp },
          { label: "Multi-file", value: multiFields, icon: Layers },
        ]}
      />

      <Card p={0}>
        <Tabs defaultValue="import" variant="outline" radius="md">
          <Box px="md" pt="md">
            <Tabs.List>
              <Tabs.Tab value="import" leftSection={<ArrowDownToLine size={16} />}>
                Import
              </Tabs.Tab>
              <Tabs.Tab value="export" leftSection={<ArrowUpFromLine size={16} />}>
                Export
              </Tabs.Tab>
              <Tabs.Tab value="intercity" leftSection={<TrainFront size={16} />}>
                Intercity
              </Tabs.Tab>
              <Tabs.Tab value="other" leftSection={<FolderOpen size={16} />}>
                Other
              </Tabs.Tab>
            </Tabs.List>
          </Box>

          {(["import", "export", "intercity", "other"] as const).map((tab) => (
            <Tabs.Panel key={tab} value={tab}>
              <Stack gap={0}>
                <Box px="md" pt="md" pb="sm" w="100%">
                  <TextInput
                    placeholder="Search by code, label, or file key…"
                    leftSection={<Search size={18} />}
                    value={query}
                    onChange={(e) => setQuery(e.currentTarget.value)}
                    rightSection={
                      query ? (
                        <ActionIcon
                          size="sm"
                          color="gray"
                          variant="transparent"
                          onClick={() => setQuery("")}
                          aria-label="Clear search"
                        >
                          <X size={16} />
                        </ActionIcon>
                      ) : null
                    }
                    style={{ maxWidth: 420 }}
                  />
                </Box>

                <Box px="md" pb="md" w="100%">
                  {gridStatus === "error" ? (
                    <Card withBorder p="lg">
                      <Stack gap="xs" align="center" ta="center">
                        <Text fw={600} c="red">
                          Failed to load settings.
                        </Text>
                        <Text size="sm" c="dimmed">
                          {error instanceof Error ? error.message : "Unknown error."}
                        </Text>
                        <Button
                          variant="light"
                          size="xs"
                          onClick={() => void refetch()}
                        >
                          Retry
                        </Button>
                      </Stack>
                    </Card>
                  ) : gridStatus === "loading" ? (
                    <SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
                      {Array.from({ length: 6 }).map((_, i) => (
                        <Card key={i} withBorder p="md" h={168} />
                      ))}
                    </SimpleGrid>
                  ) : byCategory[tab].length === 0 ? (
                    <Card withBorder p="xl">
                      <Stack gap={4} align="center" ta="center" c="dimmed">
                        <Inbox size={28} />
                        <Text size="sm">
                          {query.trim()
                            ? "No file upload settings match your search."
                            : "No file upload settings in this category."}
                        </Text>
                      </Stack>
                    </Card>
                  ) : (
                    <SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
                      {byCategory[tab].map((setting) => (
                        <SettingCard key={setting.id} setting={setting} />
                      ))}
                    </SimpleGrid>
                  )}
                </Box>
              </Stack>
            </Tabs.Panel>
          ))}
        </Tabs>
      </Card>

      <BehaviorReferenceCard />
    </PageContainer>
  );
}

function SettingCard({ setting }: { setting: FileUploadSetting }) {
  const required = setting.fields.filter((f) => f.isRequired).length;
  const multi = setting.fields.filter((f) => f.isMultiple).length;
  const maxSize = Math.max(0, ...setting.fields.map((f) => f.maxSizeMb));

  return (
    <Card withBorder radius="md" p="md" h="100%">
      <Stack gap="sm" h="100%">
        <Group gap="sm" wrap="nowrap" align="flex-start">
          <ThemeIcon size={40} radius="md" variant="light" color="edr-green">
            <FileUp size={18} />
          </ThemeIcon>
          <Stack gap={2} style={{ minWidth: 0, flex: 1 }}>
            <Text size="sm" fw={600} lh={1.25}>
              {setting.label}
            </Text>
            <Text size="xs" c="dimmed" lineClamp={2}>
              {setting.description ?? "No description"}
            </Text>
          </Stack>
        </Group>

        <Group gap={6} wrap="wrap">
          <Badge variant="light" color="gray" tt="capitalize">
            {setting.entity ?? "—"}
          </Badge>
          <Badge variant="light" color="edr-green">
            {setting.fields.length} field{setting.fields.length === 1 ? "" : "s"}
          </Badge>
          {required > 0 && (
            <Badge variant="light" color="orange">
              {required} required
            </Badge>
          )}
          {multi > 0 && (
            <Badge variant="light" color="blue">
              {multi} multi
            </Badge>
          )}
        </Group>

        <Group gap={6} wrap="nowrap">
          <Code style={{ flex: 1, minWidth: 0 }}>
            <Text truncate span size="xs">
              {setting.code}
            </Text>
          </Code>
        </Group>

        <Group gap={6} c="dimmed">
          <HardDrive size={14} />
          <Text size="xs">{maxSize ? `Max ${maxSize} MB per file` : "No size limit set"}</Text>
        </Group>

        <Group justify="flex-end" mt="auto">
          <ManageFileUploadFieldsDialog setting={setting}>
            <Button variant="default" size="xs" leftSection={<Paperclip size={14} />}>
              Fields
            </Button>
          </ManageFileUploadFieldsDialog>
        </Group>
      </Stack>
    </Card>
  );
}

/**
 * Static reference: how `min_files` / `max_files` are derived from the
 * Required × Multiple toggles. Documentation aid for whoever wires uploaders.
 */
function BehaviorReferenceCard() {
  const rows: { required: boolean; multiple: boolean; min: string; max: string }[] =
    [
      { required: false, multiple: false, min: "0", max: "1" },
      { required: true, multiple: false, min: "1", max: "1" },
      { required: false, multiple: true, min: "0", max: "field.maxFiles" },
      { required: true, multiple: true, min: "1", max: "field.maxFiles" },
    ];

  return (
    <Card>
      <Stack gap="xs">
        <Text fw={600}>Required × Multiple behavior</Text>
        <Text size="sm" c="dimmed">
          Min and max file counts are derived from these two toggles. The
          &quot;Max files&quot; you set on a field is only used when{" "}
          <Text span fw={600}>
            Multiple
          </Text>{" "}
          is on.
        </Text>

        <Table mt="sm" striped withRowBorders={false} verticalSpacing="xs">
          <Table.Thead>
            <Table.Tr>
              <Table.Th>Required</Table.Th>
              <Table.Th>Multiple</Table.Th>
              <Table.Th>min_files</Table.Th>
              <Table.Th>max_files</Table.Th>
            </Table.Tr>
          </Table.Thead>
          <Table.Tbody>
            {rows.map((r) => (
              <Table.Tr key={`${r.required}-${r.multiple}`}>
                <Table.Td>
                  <Badge variant="light" color={r.required ? "edr-green" : "gray"}>
                    {r.required ? "Required" : "Optional"}
                  </Badge>
                </Table.Td>
                <Table.Td>
                  <Badge variant="light" color={r.multiple ? "edr-green" : "gray"}>
                    {r.multiple ? "Multiple" : "Single"}
                  </Badge>
                </Table.Td>
                <Table.Td>
                  <Code>{r.min}</Code>
                </Table.Td>
                <Table.Td>
                  <Code>{r.max}</Code>
                </Table.Td>
              </Table.Tr>
            ))}
          </Table.Tbody>
        </Table>

        <Text size="xs" c="dimmed">
          Helpers <Code>getMinFiles</Code> and <Code>getEffectiveMaxFiles</Code>{" "}
          live in <Code>@/types/fileUploadSettings</Code> — use them when wiring
          real uploaders. Example: a field with <Code>isRequired=false</Code>,{" "}
          <Code>isMultiple=true</Code>, <Code>maxFiles=5</Code> gives min{" "}
          <Code>
            {getMinFiles({
              isRequired: false,
            })}
          </Code>{" "}
          …5.
        </Text>
      </Stack>
    </Card>
  );
}
