/*
 * @Author: 赵伟
 * @Date: 2024-04-11 16:31:18
 * @Description: 选择数据集、模型、镜像
 */

import KFModal from '@/components/KFModal';
import { CommonTabKeys } from '@/enums';
import { to } from '@/utils/promise';
import { Icon } from '@umijs/max';
import type { GetRef, ModalProps, TreeDataNode, TreeProps } from 'antd';
import { Input, Tabs, Tree } from 'antd';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { MirrorVersion, ResourceSelectorType, selectorTypeConfig } from './config';
import styles from './index.less';
export { ResourceSelectorType, selectorTypeConfig };

// 选择数据集\模型\镜像的返回类型
export type ResourceSelectorResponse = {
  id: number; // 数据集\模型\镜像 id
  name: string; // 数据集\模型\镜像 name
  version: string; // 数据集\模型\镜像版本
  path: string; // 数据集\模型\镜像版本路径
  activeTab: CommonTabKeys; // 是我的还是公开的
};

type ResourceGroup = {
  id: number; // 数据集\模型\镜像 id
  name: string; // 数据集\模型\镜像 name
};

type ResourceFile = {
  id: number; // 文件 id
  file_name: string; // 文件 name
};

export interface ResourceSelectorModalProps extends Omit<ModalProps, 'onOk'> {
  type: ResourceSelectorType; // 数据集\模型\镜像
  defaultExpandedKeys?: React.Key[];
  defaultCheckedKeys?: React.Key[];
  defaultActiveTab?: CommonTabKeys;
  onOk?: (params: ResourceSelectorResponse | undefined) => void;
}

type TreeRef = GetRef<typeof Tree<TreeDataNode>>;

// list 数据转成 treeData
const convertToTreeData = (list: ResourceGroup[]): TreeDataNode[] => {
  return list.map((v) => ({
    title: v.name,
    key: v.id,
    isLeaf: false,
    checkable: false,
  }));
};

// 版本数据转成 treeData
const convertVersionToTreeData = (parentId: number) => {
  return (item: string | MirrorVersion): TreeDataNode => {
    if (typeof item === 'string') {
      return {
        title: item,
        key: `${parentId}-${item}`,
        isLeaf: true,
        checkable: true,
      };
    } else {
      return {
        title: item.tag_name,
        key: `${parentId}-${item.id}-${item.url}`,
        isLeaf: true,
        checkable: true,
      };
    }
  };
};

// 更新树形结构的 children
const updateChildren = (parentId: number, children: TreeDataNode[]) => {
  return (node: TreeDataNode) => {
    if (node.key === parentId) {
      return {
        ...node,
        children,
      };
    }
    return node;
  };
};

// 得到数据集\模型\镜像 id 和下属版本号
const getIdAndVersion = (versionKey: string) => {
  const index = versionKey.indexOf('-');
  const id = Number(versionKey.slice(0, index));
  const version = versionKey.slice(index + 1);
  return {
    id,
    version,
  };
};

function ResourceSelectorModal({
  type,
  defaultExpandedKeys = [],
  defaultCheckedKeys = [],
  defaultActiveTab = CommonTabKeys.Private,
  onOk,
  ...rest
}: ResourceSelectorModalProps) {
  const [activeTab, setActiveTab] = useState<string>(defaultActiveTab);
  const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
  const [checkedKeys, setCheckedKeys] = useState<React.Key[]>([]);
  const [loadedKeys, setLoadedKeys] = useState<React.Key[]>([]);
  const [originTreeData, setOriginTreeData] = useState<TreeDataNode[]>([]);
  const [files, setFiles] = useState<ResourceFile[]>([]);
  const [versionPath, setVersionPath] = useState('');
  const [searchText, setSearchText] = useState('');
  const [fisrtLoadList, setFisrtLoadList] = useState(false);
  const [fisrtLoadVersions, setFisrtLoadVersions] = useState(false);
  const treeRef = useRef<TreeRef>(null);
  const config = selectorTypeConfig[type];

  useEffect(() => {
    setExpandedKeys([]);
    setCheckedKeys([]);
    setLoadedKeys([]);
    setFiles([]);
    setVersionPath('');
    setSearchText('');
    getTreeData();
  }, [activeTab, type]);

  const treeData = useMemo(
    () =>
      originTreeData.filter((v) =>
        (v.title as string).toLowerCase()?.includes(searchText.toLowerCase()),
      ),
    [originTreeData, searchText],
  );

  // 获取数据集\模型\镜像列表
  const getTreeData = async () => {
    const available_range = activeTab === CommonTabKeys.Private ? 0 : 1;
    const params = {
      page: 0,
      size: 1000,
      [config.litReqParamKey]: available_range,
    };
    const getListReq = config.getList;
    const [res] = await to(getListReq(params));
    if (res) {
      const list = res.data?.content || [];
      const treeData = convertToTreeData(list);
      setOriginTreeData(treeData);

      // 恢复上一次的 Expand 操作
      restoreLastExpand();
    } else {
      setOriginTreeData([]);
    }
  };

  // 获取数据集\模型\镜像版本列表
  const getVersions = async (parentId: number) => {
    const getVersionsReq = config.getVersions;
    const [res, error] = await to(getVersionsReq(parentId));
    if (res) {
      const list = config.handleVersionResponse(res);
      const children = list.map(convertVersionToTreeData(parentId));
      // 更新 treeData children
      setOriginTreeData((prev) => prev.map(updateChildren(parentId, children)));
      // 缓存 loadedKeys
      const index = loadedKeys.find((v) => v === parentId);
      if (!index) {
        setLoadedKeys((prev) => prev.concat(parentId));
      }
      // 恢复上一次的 Check 操作
      restoreLastCheck(parentId);
    } else {
      setExpandedKeys([]);
      return Promise.reject(error);
    }
  };

  // 获取版本下的文件
  const getFiles = async (id: number, version: string) => {
    const getFilesReq = config.getFiles;
    const paramsKey = config.fileReqParamKey;
    const params = { version: version, [paramsKey]: id };
    const [res] = await to(getFilesReq(params));
    if (res) {
      setVersionPath(res.data?.path || '');
      setFiles(res.data?.content || []);
    } else {
      setVersionPath('');
      setFiles([]);
    }
  };

  // 动态加载 tree children
  const onLoadData = ({ key, children }: TreeDataNode) => {
    if (children) {
      return Promise.resolve();
    } else {
      return getVersions(key as number);
    }
  };

  // 扩展
  const onExpand: TreeProps['onExpand'] = (expandedKeysValue) => {
    const lastKeys = expandedKeysValue.slice(-1);
    setExpandedKeys(lastKeys);
  };

  // 选中
  const onCheck: TreeProps['onCheck'] = (checkedKeysValue) => {
    const lastKeys = (checkedKeysValue as React.Key[]).slice(-1);
    setCheckedKeys(lastKeys);
    if (lastKeys.length) {
      const last = lastKeys[0] as string;
      const { id, version } = getIdAndVersion(last);
      getFiles(id, version);
    } else {
      setFiles([]);
    }
  };

  // 恢复上一次的 Expand 操作
  // 判断是否有 defaultExpandedKeys，如果有，设置 expandedKeys
  // fisrtLoadList 标志位
  const restoreLastExpand = () => {
    if (!fisrtLoadList && defaultExpandedKeys.length > 0) {
      setTimeout(() => {
        setExpandedKeys(defaultExpandedKeys);
        setFisrtLoadList(true);
        setTimeout(() => {
          treeRef.current?.scrollTo({ key: defaultExpandedKeys[0], align: 'bottom' });
        }, 100);
      }, 0);
    }
  };

  // 恢复上一次的 Check 操作
  // 判断是否有 defaultCheckedKeys，如果有，设置 checkedKeys，并且调用获取文件列表接口
  // fisrtLoadVersions 标志位
  const restoreLastCheck = (parentId: number) => {
    if (!fisrtLoadVersions && defaultCheckedKeys.length > 0) {
      const last = defaultCheckedKeys[0] as string;
      const { id, version } = getIdAndVersion(last);
      // 判断正在打开的 id 和 defaultCheckedKeys 的 id 是否一致
      if (id === parentId) {
        setTimeout(() => {
          setCheckedKeys(defaultCheckedKeys);
          getFiles(id, version);
          setFisrtLoadVersions(true);
          setTimeout(() => {
            treeRef?.current?.scrollTo({
              key: defaultCheckedKeys[0],
              align: 'bottom',
            });
          }, 100);
        }, 0);
      }
    }
  };

  // 提交
  const handleOk = () => {
    if (checkedKeys.length > 0) {
      const last = checkedKeys[0] as string;
      const { id, version } = getIdAndVersion(last);
      const name = (treeData.find((v) => Number(v.key) === id)?.title ?? '') as string;
      const res = {
        id,
        name,
        path: versionPath,
        version,
        activeTab: activeTab as CommonTabKeys,
      };
      onOk?.(res);
    } else {
      onOk?.(undefined);
    }
  };

  const title = `选择${config.name}`;
  const palceholder = `请输入${config.name}名称`;
  const fileTitle =
    type === ResourceSelectorType.Mirror ? '已选镜像' : `已选${config.name}文件（${files.length}）`;
  const tabItems = config.tabItems;
  const titleImg = config.modalIcon;

  return (
    <KFModal {...rest} title={title} image={titleImg} onOk={handleOk} width={920} destroyOnClose>
      <div>
        <Tabs
          activeKey={activeTab}
          items={tabItems}
          onChange={setActiveTab}
          className={styles['model-tabs']}
        />
        <div className={styles['model-selector']}>
          <div className={styles['model-selector__left']}>
            <Input
              className={styles['model-selector__left__search']}
              placeholder={palceholder}
              allowClear
              variant="borderless"
              value={searchText}
              onChange={(e) => setSearchText(e.target.value)}
              prefix={<Icon icon="local:magnifying-glass" style={{ height: '15px' }} />}
            />
            <Tree
              ref={treeRef}
              rootStyle={{ backgroundColor: 'transparent' }}
              loadData={onLoadData}
              treeData={treeData}
              onCheck={onCheck}
              checkedKeys={checkedKeys}
              multiple={false}
              selectable={false}
              height={324}
              loadedKeys={loadedKeys}
              expandedKeys={expandedKeys}
              onExpand={onExpand}
              checkable
            />
          </div>
          <div className={styles['model-selector__right']}>
            <div className={styles['model-selector__right__title']}>{fileTitle}</div>
            <div className={styles['model-selector__right__files']}>
              {files.map((v) => (
                <div key={v.id} className={styles['model-selector__right__files__file']}>
                  {v.file_name}
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </KFModal>
  );
}

export default ResourceSelectorModal;
