import { useEffect, useMemo, useRef, useState } from "react";
import {
  ActionIcon,
  Box,
  Button,
  Group,
  Stack,
  Text,
  ThemeIcon,
  UnstyledButton,
} from "@mantine/core";
import { Eye, FileText, Trash2, UploadCloud } from "lucide-react";
import { isViewable } from "@edr/ui-common";

export interface PhasedFileDropzoneProps {
  label: string;
  description?: string;
  value: File | null;
  onChange: (file: File | null) => void;
  accept?: string;
  replaceMode?: boolean;
  onPreview?: (file: { name: string; url: string; mimeType?: string | null }) => void;
  disabled?: boolean;
}

function formatBytes(bytes: number): string {
  if (bytes === 0) return "0 B";
  const k = 1024;
  const sizes = ["B", "KB", "MB", "GB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return `${parseFloat((bytes / k ** i).toFixed(1))} ${sizes[i]}`;
}

function isImageFile(file: File): boolean {
  if (file.type.startsWith("image/")) return true;
  const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
  return ["png", "jpg", "jpeg", "webp", "gif", "bmp", "svg"].includes(ext);
}

export function PhasedFileDropzone({
  label,
  description,
  value,
  onChange,
  accept = "application/pdf,image/*",
  replaceMode = false,
  onPreview,
  disabled = false,
}: PhasedFileDropzoneProps) {
  const inputRef = useRef<HTMLInputElement>(null);
  const [dragOver, setDragOver] = useState(false);

  const previewUrl = useMemo(
    () => (value ? URL.createObjectURL(value) : null),
    [value],
  );

  useEffect(() => {
    return () => {
      if (previewUrl) URL.revokeObjectURL(previewUrl);
    };
  }, [previewUrl]);

  const pickFile = (file: File | null) => {
    if (disabled) return;
    onChange(file);
  };

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    setDragOver(false);
    if (disabled) return;
    const file = e.dataTransfer.files[0];
    if (file) pickFile(file);
  };

  if (value && previewUrl) {
    const canPreview = onPreview && isViewable({ name: value.name, url: previewUrl, mimeType: value.type });
    const image = isImageFile(value);

    return (
      <Stack gap={6}>
        <Text size="sm" fw={600}>
          {label}
        </Text>
        <Box
          p="sm"
          style={{
            borderRadius: 12,
            border: "1px solid var(--mantine-color-edr-green-4)",
            background:
              "linear-gradient(135deg, var(--mantine-color-edr-green-0) 0%, #fff 70%)",
          }}
        >
          <Group justify="space-between" wrap="nowrap" align="center">
            <Group gap={12} wrap="nowrap" style={{ minWidth: 0 }}>
              {image ? (
                <UnstyledButton
                  onClick={() =>
                    canPreview && onPreview?.({ name: value.name, url: previewUrl, mimeType: value.type })
                  }
                  style={{
                    width: 52,
                    height: 52,
                    flexShrink: 0,
                    borderRadius: 10,
                    overflow: "hidden",
                    border: "1px solid var(--mantine-color-gray-3)",
                    cursor: canPreview ? "pointer" : "default",
                  }}
                >
                  <img
                    src={previewUrl}
                    alt=""
                    style={{ width: "100%", height: "100%", objectFit: "cover" }}
                  />
                </UnstyledButton>
              ) : (
                <ThemeIcon variant="light" color="edr-green" radius="md" size={52}>
                  <FileText size={22} />
                </ThemeIcon>
              )}
              <Box style={{ minWidth: 0 }}>
                <Text size="xs" fw={700} c="edr-green" tt="uppercase">
                  Ready to upload
                </Text>
                <Text size="sm" fw={600} truncate>
                  {value.name}
                </Text>
                <Text size="xs" c="dimmed">
                  {formatBytes(value.size)}
                </Text>
              </Box>
            </Group>
            <Group gap={6} wrap="nowrap">
              {canPreview ? (
                <Button
                  size="compact-xs"
                  variant="default"
                  leftSection={<Eye size={13} />}
                  onClick={() =>
                    onPreview({ name: value.name, url: previewUrl, mimeType: value.type })
                  }
                >
                  Preview
                </Button>
              ) : null}
              <ActionIcon
                variant="subtle"
                color="red"
                radius="md"
                aria-label="Remove file"
                onClick={() => pickFile(null)}
                disabled={disabled}
              >
                <Trash2 size={15} />
              </ActionIcon>
            </Group>
          </Group>
        </Box>
      </Stack>
    );
  }

  return (
    <Stack gap={6}>
      <Text size="sm" fw={600}>
        {label}
      </Text>
      {description ? (
        <Text size="xs" c="dimmed">
          {description}
        </Text>
      ) : null}
      <Box
        onDragOver={(e) => {
          e.preventDefault();
          if (!disabled) setDragOver(true);
        }}
        onDragLeave={() => setDragOver(false)}
        onDrop={handleDrop}
        onClick={() => !disabled && inputRef.current?.click()}
        style={{
          borderRadius: 12,
          border: `2px dashed ${
            dragOver
              ? "var(--mantine-color-edr-green-5)"
              : "var(--mantine-color-gray-4)"
          }`,
          background: dragOver
            ? "var(--mantine-color-edr-green-0)"
            : "var(--mantine-color-gray-0)",
          padding: "28px 20px",
          textAlign: "center",
          cursor: disabled ? "not-allowed" : "pointer",
          opacity: disabled ? 0.6 : 1,
          transition: "border-color 120ms ease, background 120ms ease",
        }}
      >
        <input
          ref={inputRef}
          type="file"
          accept={accept}
          hidden
          disabled={disabled}
          onChange={(e) => pickFile(e.target.files?.[0] ?? null)}
        />
        <Stack gap={8} align="center">
          <ThemeIcon
            variant="light"
            color={dragOver ? "edr-green" : "gray"}
            radius="xl"
            size={48}
          >
            <UploadCloud size={24} />
          </ThemeIcon>
          <Box>
            <Text size="sm" fw={600}>
              {dragOver
                ? "Drop to upload"
                : replaceMode
                  ? "Drag & drop to replace"
                  : "Drag & drop your file here"}
            </Text>
            <Text size="xs" c="dimmed" mt={4}>
              or <span style={{ color: "var(--mantine-color-edr-green-7)", fontWeight: 600 }}>browse</span>{" "}
              — PDF or image
            </Text>
          </Box>
        </Stack>
      </Box>
    </Stack>
  );
}

export interface PhasedMultiFileDropzoneProps {
  label: string;
  description?: string;
  value: File[];
  onChange: (files: File[]) => void;
  accept?: string;
  replaceMode?: boolean;
  disabled?: boolean;
}

export function PhasedMultiFileDropzone({
  label,
  description,
  value,
  onChange,
  accept = "application/pdf,image/*",
  replaceMode = false,
  disabled = false,
}: PhasedMultiFileDropzoneProps) {
  const inputRef = useRef<HTMLInputElement>(null);
  const [dragOver, setDragOver] = useState(false);

  const addFiles = (incoming: FileList | File[]) => {
    if (disabled) return;
    const next = [...value];
    for (const file of Array.from(incoming)) {
      if (!next.some((f) => f.name === file.name && f.size === file.size)) {
        next.push(file);
      }
    }
    onChange(next);
  };

  const removeAt = (index: number) => {
    if (disabled) return;
    onChange(value.filter((_, i) => i !== index));
  };

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    setDragOver(false);
    if (e.dataTransfer.files.length > 0) addFiles(e.dataTransfer.files);
  };

  return (
    <Stack gap={6}>
      <Text size="sm" fw={600}>
        {label}
      </Text>
      {description ? (
        <Text size="xs" c="dimmed">
          {description}
        </Text>
      ) : null}

      {value.length > 0 ? (
        <Stack gap={8}>
          {value.map((file, index) => (
            <Box
              key={`${file.name}-${file.size}-${index}`}
              p="sm"
              style={{
                borderRadius: 12,
                border: "1px solid var(--mantine-color-edr-green-4)",
                background:
                  "linear-gradient(135deg, var(--mantine-color-edr-green-0) 0%, #fff 70%)",
              }}
            >
              <Group justify="space-between" wrap="nowrap" align="center">
                <Group gap={12} wrap="nowrap" style={{ minWidth: 0 }}>
                  <ThemeIcon variant="light" color="edr-green" radius="md" size={44}>
                    <FileText size={18} />
                  </ThemeIcon>
                  <Box style={{ minWidth: 0 }}>
                    <Text size="xs" fw={700} c="edr-green" tt="uppercase">
                      Ready to upload
                    </Text>
                    <Text size="sm" fw={600} truncate>
                      {file.name}
                    </Text>
                    <Text size="xs" c="dimmed">
                      {formatBytes(file.size)}
                    </Text>
                  </Box>
                </Group>
                <ActionIcon
                  variant="subtle"
                  color="red"
                  radius="md"
                  aria-label="Remove file"
                  onClick={() => removeAt(index)}
                  disabled={disabled}
                >
                  <Trash2 size={15} />
                </ActionIcon>
              </Group>
            </Box>
          ))}
        </Stack>
      ) : null}

      <Box
        onDragOver={(e) => {
          e.preventDefault();
          if (!disabled) setDragOver(true);
        }}
        onDragLeave={() => setDragOver(false)}
        onDrop={handleDrop}
        onClick={() => !disabled && inputRef.current?.click()}
        style={{
          borderRadius: 12,
          border: `2px dashed ${
            dragOver
              ? "var(--mantine-color-edr-green-5)"
              : "var(--mantine-color-gray-4)"
          }`,
          background: dragOver
            ? "var(--mantine-color-edr-green-0)"
            : "var(--mantine-color-gray-0)",
          padding: "28px 20px",
          textAlign: "center",
          cursor: disabled ? "not-allowed" : "pointer",
          opacity: disabled ? 0.6 : 1,
          transition: "border-color 120ms ease, background 120ms ease",
        }}
      >
        <input
          ref={inputRef}
          type="file"
          accept={accept}
          multiple
          hidden
          disabled={disabled}
          onChange={(e) => {
            if (e.target.files?.length) addFiles(e.target.files);
            e.target.value = "";
          }}
        />
        <Stack gap={8} align="center">
          <ThemeIcon
            variant="light"
            color={dragOver ? "edr-green" : "gray"}
            radius="xl"
            size={48}
          >
            <UploadCloud size={24} />
          </ThemeIcon>
          <Box>
            <Text size="sm" fw={600}>
              {dragOver
                ? "Drop to add files"
                : replaceMode
                  ? "Drag & drop to replace declaration files"
                  : "Drag & drop declaration files here"}
            </Text>
            <Text size="xs" c="dimmed" mt={4}>
              or{" "}
              <span style={{ color: "var(--mantine-color-edr-green-7)", fontWeight: 600 }}>
                browse
              </span>{" "}
              — select one or more PDF or image files
            </Text>
          </Box>
        </Stack>
      </Box>
    </Stack>
  );
}
