import { ChangeEvent, useEffect, useMemo, useRef, useState } from 'react';
import { Controller, useForm } from 'react-hook-form';

import { Button } from '~/shared/components/button/Button';
import { Modal, ModalRegion } from '~/shared/components/modal';
import { Select, type SelectOption } from '~/shared/components/select/Select';
import { Tree, type TreeItemType, type TreeRef } from '~/shared/components/tree/Tree';

import { fetchFolderList, fetchRegions } from '../api/imagery';
import { useAerialChunkUpload, type UploadingFile } from '../hooks/useAerialChunkUpload';

type AerialRegisterModalProps = {
  isOpen: boolean;
  onClose: () => void;
  onUploadSuccess?: () => void;
};

type FormValues = {
  type: string;
  region: string;
  folderPath: string;
};

const TYPE_OPTIONS: SelectOption[] = [
  { value: 'mapFrame', label: '도곽' },
];

const formatFileSize = (bytes: number) => {
  if (bytes === 0) return '0B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))}${sizes[i]}`;
};

const ProgressBar = ({ progress }: { progress: number }) => {
  return (
    <div className="flex-1 h-2 bg-dabeeo-gray-eb overflow-hidden">
      <div
        className="h-full bg-primary transition-all duration-300"
        style={{ width: `${progress}%` }}
      />
    </div>
  );
};

const FileItem = ({
  file,
  folderPath,
  onRemove,
}: {
  file: UploadingFile;
  folderPath: string;
  onRemove: (id: string) => void;
}) => {
  const fullPath = folderPath ? `${folderPath}/${file.fileName}` : file.fileName;
  return (
    <div className="flex items-center gap-2 py-1">
      <span className="text-sm text-dabeeo-black-34 truncate flex-1">{fullPath}</span>
      <button
        type="button"
        onClick={() => onRemove(file.id)}
        className="text-dabeeo-gray-99 hover:text-dabeeo-black-34 cursor-pointer"
      >
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
          <path
            d="M12.5 4L4 12.5M4 4L12.5 12.5"
            stroke="currentColor"
            strokeWidth="1.5"
            strokeLinecap="round"
          />
        </svg>
      </button>
    </div>
  );
};

export const AerialRegisterModal = ({ isOpen, onClose, onUploadSuccess }: AerialRegisterModalProps) => {
  const treeRef = useRef<TreeRef | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const { control, setValue, watch, reset: resetForm } = useForm<FormValues>({
    defaultValues: {
      type: 'mapFrame',
      region: '',
      folderPath: '',
    },
  });

  const selectedRegion = watch('region');
  const selectedFolder = watch('folderPath');

  const [regions, setRegions] = useState<SelectOption[]>([]);
  const [treeItems, setTreeItems] = useState<TreeItemType[]>([]);
  const [isLoadingFolders, setIsLoadingFolders] = useState(false);

  const {
    files,
    addFiles,
    startUpload,
    removeFile,
    reset: resetUpload,
    isUploading,
    isAllCompleted,
    hasFiles,
    totalSize,
    uploadedSize,
    overallProgress,
  } = useAerialChunkUpload();

  const memorizedSelectedKeys = useMemo(
    () => new Set(selectedFolder ? [selectedFolder] : []),
    [selectedFolder]
  );

  // 지역 목록 조회
  useEffect(() => {
    const loadRegions = async () => {
      try {
        const data = await fetchRegions();
        setRegions(data.map((r) => ({ value: r.code, label: r.name })));
      } catch (error) {
        console.error('Failed to load regions:', error);
      }
    };
    if (isOpen) {
      loadRegions();
    }
  }, [isOpen]);

  // 지역 선택 시 폴더 목록 조회
  useEffect(() => {
    if (!selectedRegion) {
      setTreeItems([]);
      return;
    }

    const loadFolders = async () => {
      setIsLoadingFolders(true);
      try {
        const data = await fetchFolderList(selectedRegion);
        const items: TreeItemType[] = data.folders.map((folder) => ({
          id: folder.fullPath,
          title: folder.folderNm,
          type: 'directory',
        }));
        setTreeItems(items);
      } catch (error) {
        console.error('Failed to load folders:', error);
      } finally {
        setIsLoadingFolders(false);
      }
    };
    loadFolders();
  }, [selectedRegion]);

  const handleExpandFolder = async (key: string | number) => {
    const folderPath = String(key);
    try {
      const data = await fetchFolderList(folderPath);
      data.folders.forEach((folder) => {
        const newItem: TreeItemType = {
          id: folder.fullPath,
          title: folder.folderNm,
          type: 'directory',
        };
        treeRef.current?.addItem(newItem, folderPath);
      });
    } catch (error) {
      console.error('Failed to load subfolders:', error);
    }
  };

  const handleCollapseFolder = (key: string | number) => {
    treeRef.current?.clearItemsByParentKey(key);
  };

  const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
    const selectedFiles = e.target.files;
    if (!selectedFiles || selectedFiles.length === 0) return;

    const fileArray = Array.from(selectedFiles);
    const addedFiles = addFiles(fileArray);

    // 파일 선택 즉시 업로드 시작
    startUpload(addedFiles);

    // input 초기화 (같은 파일 재선택 가능하도록)
    if (fileInputRef.current) {
      fileInputRef.current.value = '';
    }
  };

  const handleUpload = () => {
    if (!selectedFolder) {
      ModalRegion.alert({ content: '업로드할 폴더를 선택해주세요.' });
      return;
    }

    if (!hasFiles) {
      ModalRegion.alert({ content: '업로드할 파일을 선택해주세요.' });
      return;
    }

    if (isUploading) {
      ModalRegion.alert({ content: '파일 업로드가 진행 중입니다.' });
      return;
    }

    if (isAllCompleted) {
      ModalRegion.alert({
        content: '파일 업로드가 완료되었습니다.',
        onCancel: () => {
          onUploadSuccess?.();
          handleClose();
        },
      });
    }
  };

  const handleClose = () => {
    resetUpload();
    resetForm();
    setTreeItems([]);
    onClose();
  };

  const handleCancel = () => {
    if (isUploading || hasFiles) {
      ModalRegion.confirm({
        content: '업로드를 취소하시겠습니까?\n진행 중인 업로드가 중단됩니다.',
        confirmText: '예',
        cancelText: '아니오',
        onConfirm: (close) => {
          close();
          handleClose();
        },
      });
    } else {
      handleClose();
    }
  };

  const currentUploadingFile = files.find((f) => f.status === 'uploading');

  return (
    <Modal isOpen={isOpen} onOpenChange={handleCancel} isKeyboardDismissDisabled>
      {() => (
        <form onSubmit={(e) => { e.preventDefault(); handleUpload(); }}>
          <Modal.Header hasCloseButton={false}>업로드 폴더 선택</Modal.Header>
          <Modal.Body>
            <div className="flex flex-col gap-4 py-2 w-140">
              {/* 타입 선택 */}
              <div className="flex items-center gap-4">
                <label className="w-20 text-sm font-semibold text-dabeeo-black-34 shrink-0">
                  타입 선택
                </label>
                <Controller
                  name="type"
                  control={control}
                  render={({ field: { value, onChange } }) => (
                    <Select
                      items={TYPE_OPTIONS}
                      selectedKey={value}
                      onChange={onChange}
                      className="w-40"
                    />
                  )}
                />
              </div>

              {/* 지역 선택 */}
              <div className="flex items-center gap-4">
                <label className="w-20 text-sm font-semibold text-dabeeo-black-34 shrink-0">
                  지역 선택
                </label>
                <Controller
                  name="region"
                  control={control}
                  render={({ field: { value, onChange } }) => (
                    <Select
                      items={regions}
                      selectedKey={value}
                      onChange={(v) => {
                        onChange(v);
                        setValue('folderPath', '');
                      }}
                      placeholder="지역선택"
                      className="w-40"
                    />
                  )}
                />
              </div>

              {/* 폴더 선택 */}
              <div className="flex items-start gap-4">
                <label className="w-20 text-sm font-semibold text-dabeeo-black-34 shrink-0 pt-2">
                  폴더 선택
                </label>
                <div className="flex-1 border border-dabeeo-gray-be max-h-60 min-h-40 overflow-y-auto">
                  {isLoadingFolders ? (
                    <div className="flex items-center justify-center h-40 text-sm text-dabeeo-gray-99">
                      로딩 중...
                    </div>
                  ) : treeItems.length > 0 ? (
                    <Controller
                      name="folderPath"
                      control={control}
                      render={({ field: { onChange } }) => (
                        <Tree
                          ref={treeRef}
                          items={treeItems}
                          selectedKeys={memorizedSelectedKeys}
                          onExpand={(key, item) => {
                            handleExpandFolder(key);
                            onChange(String(key));
                          }}
                          onCollapse={(key) => {
                            handleCollapseFolder(key);
                          }}
                          onSelect={(key) => {
                            if (key) onChange(String(key));
                          }}
                          enableDragAndDrop={false}
                          persistSelectionOnCollapse
                        />
                      )}
                    />
                  ) : selectedRegion ? (
                    <div className="flex items-center justify-center h-40 text-sm text-dabeeo-gray-99">
                      폴더가 없습니다.
                    </div>
                  ) : (
                    <div className="flex items-center justify-center h-40 text-sm text-dabeeo-gray-99">
                      지역을 선택해주세요.
                    </div>
                  )}
                </div>
              </div>

              <p className="text-xs text-dabeeo-orange-main ml-24">
                ※ 업로드 대상 폴더를 정확하게 지정하시기 바랍니다.
              </p>

              {/* 파일명 */}
              <div className="flex items-start gap-4">
                <label className="w-20 text-sm font-semibold text-dabeeo-black-34 shrink-0 pt-2">
                  파일명 <span className="text-dabeeo-red">*</span>
                </label>
                <div className="flex-1 border border-dabeeo-gray-be p-2 min-h-10 max-h-24 overflow-y-auto">
                  {files.length > 0 ? (
                    files.map((file) => (
                      <FileItem key={file.id} file={file} folderPath={selectedFolder} onRemove={removeFile} />
                    ))
                  ) : (
                    <span className="text-sm text-dabeeo-gray-99">파일이 업로드 되면 자동 입력됩니다.</span>
                  )}
                </div>
              </div>

              {/* 파일 선택 */}
              <div className="flex items-center gap-4">
                <label className="w-20 text-sm font-semibold text-dabeeo-black-34 shrink-0">
                  파일 <span className="text-dabeeo-red">*</span>
                </label>
                <div className="flex-1 flex items-center gap-2">
                  <div className="flex-1 h-9 border border-dabeeo-gray-be px-3 flex items-center">
                    <span className="text-sm text-dabeeo-gray-99 truncate">
                      {currentUploadingFile?.fileName || ''}
                    </span>
                  </div>
                  <label
                    htmlFor="aerial-file-input"
                    className="h-9 px-4 bg-dabeeo-black-34 text-white text-sm font-medium flex items-center justify-center cursor-pointer hover:bg-dabeeo-black-47"
                  >
                    파일선택
                  </label>
                  <input
                    id="aerial-file-input"
                    ref={fileInputRef}
                    type="file"
                    accept=".tif,.tiff"
                    multiple
                    onChange={handleFileChange}
                    className="hidden"
                  />
                </div>
              </div>

              {/* 진행률 표시 */}
              {hasFiles && (
                <div className="flex items-center gap-4 ml-24">
                  <ProgressBar progress={overallProgress} />
                  <span className="text-xs text-dabeeo-black-34 w-10 text-right">{overallProgress}%</span>
                </div>
              )}

              {hasFiles && (
                <div className="text-xs text-dabeeo-gray-99 ml-24">
                  Loading {formatFileSize(uploadedSize)} / {formatFileSize(totalSize)}
                </div>
              )}
            </div>
          </Modal.Body>
          <Modal.Footer>
            <Button type="button" color="gray" size="large" onClick={handleCancel}>
              취소
            </Button>
            <Button
              type="submit"
              color="primary"
              size="large"
              isDisabled={!hasFiles || isUploading}
              isPending={isUploading}
            >
              업로드
            </Button>
          </Modal.Footer>
        </form>
      )}
    </Modal>
  );
};
