"use client";

import { useCallback, useEffect, useMemo, useState, type ReactNode } from "react";
import { CheckOutlined, CloseOutlined } from "@ant-design/icons";
import { Button, Empty, Modal, TreeSelect, message } from "antd";

import { useI18n } from "@/i18n";
import { authFetch } from "@/utils/authFetch";
import {
  getUserFileList,
  ROOT_PARENT_ID,
  USER_FILE_PAGE_SIZE,
  type UserFileItem,
  type UserFileListResponse,
  type UserFileMutationResponse,
} from "@/utils/userFileLibrary";

interface SaveToAssetLibraryModalProps {
  open: boolean;
  mediaUrl: string | null;
  onClose: () => void;
  onSaved?: (folderId: number) => void | Promise<void>;
}

interface FolderTreeNode {
  title: ReactNode;
  value: number;
  key: number;
  isLeaf: boolean;
  children?: FolderTreeNode[];
}

function SaveToAssetLibraryModalHeader({
  title,
  onClose,
}: {
  title: string;
  onClose: () => void;
}) {
  const { t } = useI18n();

  return (
    <div className="flex h-12 shrink-0 items-center justify-between px-4">
      <h2 className="text-sm font-semibold text-[var(--text-primary)]">{title}</h2>
      <Button
        type="text"
        aria-label={t("common.close")}
        icon={<CloseOutlined className="text-[14px]" />}
        onClick={onClose}
        className="!flex !h-8 !w-8 !items-center !justify-center !rounded-lg !p-0 !text-[var(--text-muted)] hover:!bg-[var(--surface-hover)] hover:!text-[var(--text-primary)]"
      />
    </div>
  );
}

export function SaveToAssetLibraryModal({
  open,
  mediaUrl,
  onClose,
  onSaved,
}: SaveToAssetLibraryModalProps) {
  const { t } = useI18n();
  const [foldersByParentId, setFoldersByParentId] = useState<Record<number, UserFileItem[]>>({});
  const [loadedFolderIds, setLoadedFolderIds] = useState<Set<number>>(new Set());
  const [loadingFolderIds, setLoadingFolderIds] = useState<Set<number>>(new Set());
  const [selectedFolderId, setSelectedFolderId] = useState(0);
  const [expandedFolderIds, setExpandedFolderIds] = useState<(string | number)[]>([]);
  const [submitting, setSubmitting] = useState(false);

  const rootFolders = foldersByParentId[ROOT_PARENT_ID] || [];

  const folderIdExists = useCallback((folderId: number) => {
    if (folderId === ROOT_PARENT_ID) return false;
    return Object.values(foldersByParentId).some((folders) => folders.some((folder) => folder.id === folderId));
  }, [foldersByParentId]);

  const loadFolderChildren = useCallback(async (folderId: number) => {
    setLoadingFolderIds((current) => new Set(current).add(folderId));
    try {
      const params = new URLSearchParams({
        parentId: String(folderId),
        keyword: "",
        page: "1",
        pageSize: String(USER_FILE_PAGE_SIZE),
      });
      const response = await authFetch(`/api/popi/user-file/list?${params.toString()}`);
      const payload = (await response.json().catch(() => null)) as UserFileListResponse | null;
      if (!response.ok || !payload?.success) {
        throw new Error(payload?.error || t("assetLibrary.loadFailed"));
      }

      const folders = getUserFileList(payload.data).filter((item) => item.nodeType === "folder");
      setFoldersByParentId((current) => ({ ...current, [folderId]: folders }));
      setLoadedFolderIds((current) => new Set(current).add(folderId));
    } catch (err) {
      const messageText = err instanceof Error ? err.message : t("assetLibrary.loadFailed");
      void message.error(messageText);
    } finally {
      setLoadingFolderIds((current) => {
        const next = new Set(current);
        next.delete(folderId);
        return next;
      });
    }
  }, [t]);

  useEffect(() => {
    if (!open) return;
    setFoldersByParentId({});
    setLoadedFolderIds(new Set());
    setLoadingFolderIds(new Set());
    setSelectedFolderId(0);
    setExpandedFolderIds([]);
    setSubmitting(false);
    void loadFolderChildren(ROOT_PARENT_ID);
  }, [loadFolderChildren, open]);

  useEffect(() => {
    if (!open || selectedFolderId !== 0 || rootFolders.length === 0) return;
    setSelectedFolderId(rootFolders[0].id);
  }, [open, rootFolders, selectedFolderId]);

  const treeData = useMemo(() => {
    const buildNodes = (parentId: number): FolderTreeNode[] => {
      const folders = foldersByParentId[parentId] || [];
      return folders.map((folder) => {
        const loaded = loadedFolderIds.has(folder.id);
        const children = foldersByParentId[folder.id] || [];
        return {
          title: (
            <span className="flex min-w-0 flex-1 items-center justify-between gap-3">
              <span className="min-w-0 truncate">{folder.name}</span>
              {selectedFolderId === folder.id ? <CheckOutlined className="shrink-0 text-[13px]" /> : null}
            </span>
          ),
          value: folder.id,
          key: folder.id,
          isLeaf: loaded && children.length === 0,
          children: loaded && children.length > 0 ? buildNodes(folder.id) : undefined,
        };
      });
    };

    return buildNodes(ROOT_PARENT_ID);
  }, [foldersByParentId, loadedFolderIds, selectedFolderId]);

  const handleTreeExpand = useCallback((expandedKeys: (string | number)[]) => {
    setExpandedFolderIds(expandedKeys);
    expandedKeys.forEach((key) => {
      const folderId = Number(key);
      if (Number.isInteger(folderId) && folderId > 0) {
        void loadFolderChildren(folderId);
      }
    });
  }, [loadFolderChildren]);

  const handleConfirm = useCallback(async () => {
    if (submitting || !mediaUrl || !folderIdExists(selectedFolderId)) return;

    setSubmitting(true);
    try {
      const response = await authFetch("/api/popi/user-file/upload", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          parentId: selectedFolderId,
          urlList: [mediaUrl],
        }),
      });
      const payload = (await response.json().catch(() => null)) as UserFileMutationResponse | null;
      if (!response.ok || !payload?.success) {
        throw new Error(payload?.error || t("assetLibrary.saveToLibraryFailed"));
      }

      await onSaved?.(selectedFolderId);
      void message.success(t("assetLibrary.saveToLibrarySuccess"));
      onClose();
    } catch (err) {
      const messageText = err instanceof Error ? err.message : t("assetLibrary.saveToLibraryFailed");
      void message.error(messageText);
    } finally {
      setSubmitting(false);
    }
  }, [folderIdExists, mediaUrl, onClose, onSaved, selectedFolderId, submitting, t]);

  const canConfirm = Boolean(mediaUrl) && folderIdExists(selectedFolderId) && !submitting;

  return (
    <Modal
      open={open}
      title={null}
      closable={false}
      centered
      width={420}
      footer={null}
      rootClassName="[&_.ant-modal-container]:!p-0"
      onCancel={submitting ? undefined : onClose}
      className={[
        "nodrag nopan nowheel",
        "[&_.ant-modal-content]:!overflow-hidden [&_.ant-modal-content]:!rounded-lg [&_.ant-modal-content]:!border-0 [&_.ant-modal-content]:!bg-[var(--surface-1)] [&_.ant-modal-content]:!p-0 [&_.ant-modal-content]:!shadow-[var(--shadow-panel)]",
        "[&_.ant-modal-body]:!p-0",
      ].join(" ")}
    >
      <div className="text-[var(--text-primary)]">
        <SaveToAssetLibraryModalHeader
          title={t("assetLibrary.saveToLibrary")}
          onClose={() => {
            if (!submitting) onClose();
          }}
        />
        <div className="px-4 pb-4">
          <div className="mb-2 text-xs text-[var(--text-muted)]">{t("assetLibrary.uploadLocation")}</div>
          {rootFolders.length === 0 && loadedFolderIds.has(ROOT_PARENT_ID) ? (
            <div className="rounded-lg border border-[var(--border-subtle)] bg-[var(--surface-2)] py-4">
              <Empty
                image={Empty.PRESENTED_IMAGE_SIMPLE}
                description={<span className="text-xs text-[var(--text-disabled)]">{t("assetLibrary.noFolders")}</span>}
              />
            </div>
          ) : (
            <TreeSelect
              value={folderIdExists(selectedFolderId) ? selectedFolderId : undefined}
              treeData={treeData}
              loadData={(node) => Promise.resolve(loadFolderChildren(Number(node.value)))}
              loading={loadingFolderIds.size > 0}
              disabled={submitting}
              onChange={setSelectedFolderId}
              placeholder={t("assetLibrary.selectFolder")}
              treeDefaultExpandAll={false}
              treeExpandedKeys={expandedFolderIds}
              onTreeExpand={handleTreeExpand}
              className="w-full [&_.ant-select-selector]:!border-[var(--border-subtle)] [&_.ant-select-selector]:!bg-[var(--surface-2)] [&_.ant-select-selection-item]:!text-[var(--text-primary)] [&_.ant-select-selection-placeholder]:!text-[var(--text-muted)]"
              popupClassName="nodrag nopan nowheel"
            />
          )}
        </div>
        <div className="flex justify-end gap-2 px-4 pb-4">
          <Button
            disabled={submitting}
            onClick={onClose}
            className="!h-8 !rounded-lg !border-0 !bg-[var(--surface-3)] !px-4 !text-sm !font-medium !text-[var(--text-secondary)] hover:!bg-[var(--surface-hover)] hover:!text-[var(--text-primary)]"
          >
            {t("common.cancel")}
          </Button>
          <Button
            type="primary"
            loading={submitting}
            disabled={!canConfirm}
            onClick={() => void handleConfirm()}
            className="!h-8 !rounded-lg !border-0 !bg-[#3b82f6] !px-4 !text-sm !font-medium !text-white hover:!bg-[#60a5fa]"
          >
            {t("common.confirm")}
          </Button>
        </div>
      </div>
    </Modal>
  );
}
