import { useState, useRef, useCallback } from "react";
import { Popover, ActionIcon, Text, UnstyledButton } from "@mantine/core";
import {
  IconPaperclip,
  IconUpload,
  IconFile,
  IconX,
} from "@tabler/icons-react";
import { IBaseProperty } from "@/features/base/types/base.types";
import cellClasses from "@/features/base/styles/cells.module.css";
import { uploadFile } from "@/features/page/services/page-service";
import { getFileUrl } from "@/lib/config";

export type FileValue = {
  id: string;
  fileName: string;
  mimeType?: string;
  fileSize?: number;
  // `/api/files/{id}/{fileName}` — same shape the editor's attachment
  // node view uses. `getFileUrl` strips the `/api/` prefix and
  // prepends the backend host to produce a fetchable URL. Stored on
  // upload so the original filename round-trips even if the cell
  // value is moved to a row where the file's storage path no longer
  // resolves from the cell's pageId.
  url?: string;
};

function buildFileUrl(file: Pick<FileValue, "id" | "fileName" | "url">): string {
  return file.url ?? `/api/files/${file.id}/${encodeURIComponent(file.fileName)}`;
}

type CellFileProps = {
  value: unknown;
  property: IBaseProperty;
  rowId: string;
  isEditing: boolean;
  onCommit: (value: unknown) => void;
  onCancel: () => void;
};

function formatFileSize(bytes?: number): string {
  if (!bytes) return "";
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

function parseFiles(value: unknown): FileValue[] {
  if (!Array.isArray(value)) return [];
  return value.filter(
    (f): f is FileValue =>
      f && typeof f === "object" && "id" in f && "fileName" in f,
  );
}

export function CellFile({
  value,
  property,
  isEditing,
  onCommit,
  onCancel,
}: CellFileProps) {
  const files = parseFiles(value);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [uploading, setUploading] = useState(false);

  const handleRemove = useCallback(
    (fileId: string) => {
      const updated = files.filter((f) => f.id !== fileId);
      onCommit(updated.length > 0 ? updated : null);
    },
    [files, onCommit],
  );

  const handleUpload = useCallback(
    async (fileList: FileList | null) => {
      if (!fileList || fileList.length === 0) return;
      setUploading(true);

      const newFiles: FileValue[] = [...files];

      // Reuse the page-attachment upload pipeline. A base IS a page
      // (isBase=true) — the server's /files/upload endpoint accepts the
      // base's pageId, runs the standard pageAccessService.validateCanEdit
      // check (which lines up with Base edit at the space-role level per
      // the casl rules), and stores the attachment via the same flow as
      // any other page attachment.
      for (const file of Array.from(fileList)) {
        try {
          const attachment = await uploadFile(file, property.pageId);
          newFiles.push({
            id: attachment.id,
            fileName: attachment.fileName,
            mimeType: attachment.mimeType,
            fileSize: attachment.fileSize,
            url: `/api/files/${attachment.id}/${encodeURIComponent(attachment.fileName)}`,
          });
        } catch (err) {
          console.error("File upload failed:", err);
        }
      }

      setUploading(false);
      onCommit(newFiles.length > 0 ? newFiles : null);
    },
    [files, property.pageId, onCommit],
  );

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      if (e.key === "Escape") {
        e.preventDefault();
        onCancel();
      }
    },
    [onCancel],
  );

  const MAX_VISIBLE = 2;

  if (isEditing) {
    return (
      <Popover
        opened
        onClose={onCancel}
        position="bottom-start"
        width={280}
        trapFocus
      >
        <Popover.Target>
          <div style={{ width: "100%", height: "100%" }}>
            <FileList files={files} maxVisible={MAX_VISIBLE} />
          </div>
        </Popover.Target>
        <Popover.Dropdown p={8} onKeyDown={handleKeyDown}>
          {files.length === 0 && !uploading && (
            <Text size="xs" c="dimmed" mb={8}>
              No files attached
            </Text>
          )}

          {files.map((file) => (
            <div
              key={file.id}
              style={{
                display: "flex",
                alignItems: "center",
                gap: 8,
                padding: "4px 0",
                borderBottom:
                  "1px solid var(--mantine-color-default-border)",
              }}
            >
              <IconFile
                size={14}
                style={{
                  flexShrink: 0,
                  color: "var(--mantine-color-gray-6)",
                }}
              />
              <a
                href={getFileUrl(buildFileUrl(file))}
                target="_blank"
                rel="noreferrer"
                style={{
                  flex: 1,
                  minWidth: 0,
                  textDecoration: "none",
                  color: "inherit",
                }}
              >
                <Text size="xs" truncate="end" fw={500}>
                  {file.fileName}
                </Text>
                {file.fileSize != null && (
                  <Text size="xs" c="dimmed">
                    {formatFileSize(file.fileSize)}
                  </Text>
                )}
              </a>
              <ActionIcon
                variant="subtle"
                color="gray"
                size="xs"
                onClick={() => handleRemove(file.id)}
              >
                <IconX size={12} />
              </ActionIcon>
            </div>
          ))}

          <input
            ref={fileInputRef}
            type="file"
            multiple
            style={{ display: "none" }}
            onChange={(e) => {
              handleUpload(e.target.files);
              e.target.value = "";
            }}
          />

          <UnstyledButton
            onClick={() => fileInputRef.current?.click()}
            disabled={uploading}
            style={{
              display: "flex",
              alignItems: "center",
              gap: 6,
              padding: "6px 0",
              marginTop: 4,
              fontSize: "var(--mantine-font-size-xs)",
              color: uploading
                ? "var(--mantine-color-gray-5)"
                : "var(--mantine-color-blue-6)",
            }}
          >
            <IconUpload size={14} />
            {uploading ? "Uploading..." : "Add file"}
          </UnstyledButton>
        </Popover.Dropdown>
      </Popover>
    );
  }

  if (files.length === 0) {
    return <span className={cellClasses.emptyValue} />;
  }

  return <FileList files={files} maxVisible={MAX_VISIBLE} />;
}

function FileList({
  files,
  maxVisible,
}: {
  files: FileValue[];
  maxVisible: number;
}) {
  const visible = files.slice(0, maxVisible);
  const overflow = files.length - maxVisible;

  return (
    <div className={cellClasses.fileGroup}>
      {visible.map((file) => (
        <span key={file.id} className={cellClasses.fileBadge}>
          <IconPaperclip size={12} />
          {file.fileName}
        </span>
      ))}
      {overflow > 0 && (
        <span className={cellClasses.overflowCount}>+{overflow}</span>
      )}
    </div>
  );
}
