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";

import { BORDER, GREEN, INK } from "@/pages/contracts/contract-ui";

export interface PortalFileDropzoneProps {
  label: string;
  description?: string;
  value: File | null;
  onChange: (file: File | null) => void;
  accept?: string;
  onPreview?: (file: { name: string; url: string; mimeType?: string | null }) => void;
  disabled?: boolean;
  replaceMode?: 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 PortalFileDropzone({
  label,
  description,
  value,
  onChange,
  accept = "application/pdf,image/*",
  onPreview,
  disabled = false,
  replaceMode = false,
}: PortalFileDropzoneProps) {
  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 fz={13} fw={700} style={{ color: INK }}>
          {label}
        </Text>
        <Group
          gap={12}
          wrap="nowrap"
          p="sm"
          style={{
            borderRadius: 14,
            border: `1px solid ${GREEN}`,
            background: "linear-gradient(135deg, #F2FBF6 0%, #fff 75%)",
            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 ${BORDER}`,
                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, flex: 1 }}>
            <Text fz={11} fw={700} c="edr-green" tt="uppercase">
              Ready to upload
            </Text>
            <Text fz={13} fw={600} style={{ color: INK }} truncate>
              {value.name}
            </Text>
            <Text fz={11} c="dimmed">
              {formatBytes(value.size)}
            </Text>
          </Box>
          <Group gap={6} wrap="nowrap">
            {canPreview ? (
              <Button
                size="compact-xs"
                variant="light"
                color="edr-green"
                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>
      </Stack>
    );
  }

  return (
    <Stack gap={6}>
      <Text fz={13} fw={700} style={{ color: INK }}>
        {label}
      </Text>
      {description ? (
        <Text fz={12} 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: 14,
          border: `2px dashed ${dragOver ? GREEN : BORDER}`,
          background: dragOver ? "#F2FBF6" : "#FAFCFE",
          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 fz={13} fw={600} style={{ color: INK }}>
              {dragOver
                ? "Drop to upload"
                : replaceMode
                  ? "Drag & drop to replace"
                  : "Drag & drop your file here"}
            </Text>
            <Text fz={12} c="dimmed" mt={4}>
              or{" "}
              <span style={{ color: GREEN, fontWeight: 700 }}>browse</span> — PDF or
              image
            </Text>
          </Box>
        </Stack>
      </Box>
    </Stack>
  );
}
