/*
 * @Author: 赵伟
 * @Date: 2025-01-08 13:58:08
 * @Description: 自主机器学习和超参数寻优列表组件
 */

import KFIcon from '@/components/KFIcon';
import PageTitle from '@/components/PageTitle';
import { ExperimentStatus, autoMLTypeOptions } from '@/enums';
import { useCacheState } from '@/hooks/useCacheState';
import { useServerTime } from '@/hooks/useServerTime';
import { AutoMLData } from '@/pages/AutoML/types';
import { experimentStatusInfo } from '@/pages/Experiment/status';
import themes from '@/styles/theme.less';
import { type ExperimentInstance as ExperimentInstanceData } from '@/types';
import { ExperimentCompleted } from '@/utils/constant';
import { to } from '@/utils/promise';
import tableCellRender, { TableCellValueType } from '@/utils/table';
import { modalConfirm } from '@/utils/ui';
import { useNavigate } from '@umijs/max';
import {
  App,
  Button,
  ConfigProvider,
  Input,
  Table,
  Tooltip,
  type TablePaginationConfig,
  type TableProps,
} from 'antd';
import { type SearchProps } from 'antd/es/input';
import classNames from 'classnames';
import { useCallback, useEffect, useState } from 'react';
import ExperimentInstanceList from '../ExperimentInstanceList';
import { ExperimentListType, experimentListConfig } from './config';
import styles from './index.less';

export { ExperimentListType };

type ExperimentListProps = {
  type: ExperimentListType;
};

function ExperimentList({ type }: ExperimentListProps) {
  const navigate = useNavigate();
  const { message } = App.useApp();
  const [cacheState, setCacheState] = useCacheState();
  const [searchText, setSearchText] = useState(cacheState?.searchText);
  const [inputText, setInputText] = useState(cacheState?.searchText);
  const [tableData, setTableData] = useState<AutoMLData[]>([]);
  const [total, setTotal] = useState(0);
  const [experimentInsList, setExperimentInsList] = useState<ExperimentInstanceData[]>([]);
  const [expandedRowKeys, setExpandedRowKeys] = useState<number[]>([]);
  const [experimentInsTotal, setExperimentInsTotal] = useState(0);
  const [pagination, setPagination] = useState<TablePaginationConfig>(
    cacheState?.pagination ?? {
      current: 1,
      pageSize: 10,
    },
  );
  const config = experimentListConfig[type];
  const [now] = useServerTime();

  // 获取实验列表
  const getExperimentList = useCallback(
    async (skipLoading: boolean = false) => {
      const params: Record<string, any> = {
        page: pagination.current! - 1,
        size: pagination.pageSize,
        [config.nameProperty]: searchText || undefined,
      };
      const request = config.getListReq;
      const [res] = await to(request(params, skipLoading));
      if (res && res.data) {
        const { content = [], totalElements = 0 } = res.data;
        setTableData(content);
        setTotal(totalElements);
      }
    },
    [pagination, searchText, config],
  );

  // 获取实验实例列表
  const getExperimentInsList = useCallback(
    async (recordId: number, page: number, size: number, skipLoading: boolean = false) => {
      const params = {
        [config.idProperty]: recordId,
        page: page,
        size: size,
      };
      const request = config.getInsListReq;
      const [res] = await to(request(params, skipLoading));
      if (res && res.data) {
        const { content = [], totalElements = 0 } = res.data;
        try {
          if (page === 0) {
            setExperimentInsList(content);
          } else {
            setExperimentInsList((prev) => [...prev, ...content]);
          }
          setExperimentInsTotal(totalElements);
        } catch (error) {
          console.error('JSON parse error: ', error);
        }
      }
    },
    [config.getInsListReq, config.idProperty],
  );

  // 刷新实验列表状态，
  // TODO: 目前是直接刷新实验列表，后续需要优化，只刷新状态
  const refreshExperimentList = useCallback(
    (skipLoading: boolean = false) => {
      getExperimentList(skipLoading);
    },
    [getExperimentList],
  );

  // 刷新实验实例列表
  const refreshExperimentIns = useCallback(
    (experimentId: number, skipLoading: boolean = false) => {
      const length = experimentInsList.length;
      getExperimentInsList(experimentId, 0, length, skipLoading);
    },
    [getExperimentInsList, experimentInsList],
  );

  // 更新实验实例状态
  const editExperimentIns = useCallback(
    async (
      experimentId: number,
      experimentInsId: number,
      status: ExperimentStatus,
      argo_ins_name: string,
      argo_ins_ns: string,
    ) => {
      const params = {
        [config.idInsProperty]: experimentId,
        id: experimentInsId,
        status: status,
        argo_ins_name,
        argo_ins_ns,
      };
      const request = config.editInsReq;
      const [res] = await to(request(params));
      if (res && res.data) {
        refreshExperimentIns(experimentId, true);
        refreshExperimentList(true);
      }
    },
    [config, refreshExperimentIns, refreshExperimentList],
  );

  // 获取实验列表
  useEffect(() => {
    getExperimentList();
  }, [getExperimentList]);

  // expandedRowKeys 变化
  useEffect(() => {
    if (expandedRowKeys.length > 0) {
      getExperimentInsList(expandedRowKeys[0], 0, 5);
      refreshExperimentList();
    }
  }, [expandedRowKeys, getExperimentInsList, refreshExperimentList]);

  // 实验实例状态变化
  useEffect(() => {
    const handleMessage = (e: MessageEvent) => {
      const { type, payload } = e.data;
      if (type === ExperimentCompleted) {
        const { experimentId, experimentInsId, status, finishTime } = payload;
        const currentIns = experimentInsList.find((v) => v.id === experimentInsId);
        console.log(
          '实验实例状态变化',
          currentIns?.status,
          status,
          experimentId,
          experimentInsId,
          finishTime,
        );

        if (
          !currentIns ||
          currentIns.status === ExperimentStatus.Terminated ||
          currentIns.status === status
        ) {
          return;
        }

        // refreshExperimentList(true);
        // refreshExperimentIns(experimentId);
        editExperimentIns(
          experimentId,
          experimentInsId,
          status,
          currentIns.argo_ins_name,
          currentIns.argo_ins_ns,
        );

        // 修改实例的状态和结束时间
        //   setExperimentInsList((prev) =>
        //     prev.map((v) =>
        //       v.id === experimentInsId
        //         ? {
        //             ...v,
        //             status: status,
        //             finish_time: finishTime,
        //           }
        //         : v,
        //     ),
        //   );
      }
    };

    window.addEventListener('message', handleMessage);
    return () => {
      window.removeEventListener('message', handleMessage);
    };
  }, [experimentInsList, editExperimentIns]);

  // 搜索
  const onSearch: SearchProps['onSearch'] = (value) => {
    setSearchText(value);
    setPagination((prev) => ({
      ...prev,
      current: 1,
    }));
  };

  // 删除一条记录
  const deleteAutoML = async (record: AutoMLData) => {
    const request = config.deleteRecordReq;
    const [res] = await to(request(record.id));
    if (res) {
      message.success('删除成功');
      // 如果是一页的唯一数据，删除后，请求第一页的数据
      // 否则直接刷新这一页的数据
      setPagination((prev) => {
        return {
          ...prev,
          current: tableData.length === 1 ? Math.max(1, prev.current! - 1) : prev.current,
        };
      });
    }
  };

  // 处理删除
  const handleAutoMLDelete = (record: AutoMLData) => {
    modalConfirm({
      title: '删除后，该实验将不可恢复',
      content: '是否确认删除?',
      onOk: () => {
        deleteAutoML(record);
      },
    });
  };

  // 创建、编辑、复制自动机器学习
  const createAutoML = (record?: AutoMLData, isCopy: boolean = false) => {
    setCacheState({
      pagination,
      searchText,
      expandedRowKeys,
    });

    if (record) {
      if (isCopy) {
        navigate(`copy/${record.id}`);
      } else {
        navigate(`edit/${record.id}`);
      }
    } else {
      navigate(`create`);
    }
  };

  // 查看自动机器学习详情
  const gotoDetail = (record: AutoMLData) => {
    setCacheState({
      pagination,
      searchText,
      expandedRowKeys,
    });

    navigate(`info/${record.id}`);
  };

  // 启动自动机器学习
  const startAutoML = async (record: AutoMLData) => {
    const request = config.runRecordReq;
    const [res] = await to(request(record.id));
    if (res) {
      message.success('运行成功');
      setExpandedRowKeys([record.id]);
      // getExperimentInsList(record.id, 0, 5);
      // refreshExperimentList();
    }
  };

  // --------------------------- 实验实例 ---------------------------
  // 展开实例
  const handleExpandChange = (expanded: boolean, record: AutoMLData) => {
    setExperimentInsList([]);
    if (expanded) {
      setExpandedRowKeys([record.id]);
      // getExperimentInsList(record.id, 0, 5);
      // refreshExperimentList();
    } else {
      setExpandedRowKeys([]);
    }
  };

  // 跳转到实验实例详情
  const gotoInstanceInfo = (autoML: AutoMLData, record: ExperimentInstanceData) => {
    setCacheState({
      pagination,
      searchText,
      expandedRowKeys,
    });
    navigate(`instance/${autoML.id}/${record.id}`);
  };

  // 加载更多实验实例
  const loadMoreExperimentIns = () => {
    const page = Math.round(experimentInsList.length / 5);
    const recordId = expandedRowKeys[0];
    getExperimentInsList(recordId, page, 5);
  };

  // 实验实例终止
  const handleInstanceTerminate = async (experimentIns: ExperimentInstanceData) => {
    // 修改实例的状态和结束时间
    setExperimentInsList((prevList) => {
      return prevList.map((item) => {
        if (item.id === experimentIns.id) {
          return {
            ...item,
            status: ExperimentStatus.Terminated,
            finish_time: now().toISOString(),
          };
        }
        return item;
      });
    });
    // 刷新实验列表和实例列表
    refreshExperimentList(true);
    if (expandedRowKeys.length > 0) {
      refreshExperimentIns(expandedRowKeys[0]);
    }
  };
  // --------------------------- Table ---------------------------
  // 分页切换
  const handleTableChange: TableProps<AutoMLData>['onChange'] = (
    pagination,
    _filters,
    _sorter,
    { action },
  ) => {
    if (action === 'paginate') {
      setPagination(pagination);
    }
  };

  const typeColumns = [
    {
      title: '类型',
      dataIndex: 'type',
      key: 'type',
      width: '15%',
      render: tableCellRender(false, TableCellValueType.Enum, {
        options: autoMLTypeOptions,
      }),
    },
  ];

  const diffColumns = type === ExperimentListType.AutoML ? typeColumns : [];

  const columns: TableProps<AutoMLData>['columns'] = [
    {
      title: '实验名称',
      dataIndex: config.nameProperty,
      key: 'name',
      width: '30%',
      render: tableCellRender(false, TableCellValueType.Link, {
        onClick: gotoDetail,
      }),
    },
    {
      title: '实验描述',
      dataIndex: config.descProperty,
      key: 'description',
      render: tableCellRender(true),
      width: type === ExperimentListType.AutoML ? '35%' : '50%',
    },
    ...diffColumns,
    {
      title: '更新时间',
      dataIndex: 'update_time',
      key: 'update_time',
      width: '20%',
      render: tableCellRender(true, TableCellValueType.Date),
    },
    {
      title: '最近五次运行状态',
      dataIndex: 'status_list',
      key: 'status_list',
      width: 200,
      render: (text) => {
        const newText: string[] = text && text.replace(/\s+/g, '').split(',');
        return (
          <>
            {newText && newText.length > 0
              ? newText.map((item, index) => {
                  return (
                    <Tooltip
                      key={index}
                      placement="top"
                      title={experimentStatusInfo[item as ExperimentStatus].label}
                    >
                      <img
                        style={{ width: '17px', marginRight: '6px' }}
                        src={experimentStatusInfo[item as ExperimentStatus].icon}
                        draggable={false}
                        alt=""
                      />
                    </Tooltip>
                  );
                })
              : null}
          </>
        );
      },
    },
    {
      title: '操作',
      dataIndex: 'operation',
      width: 360,
      key: 'operation',
      render: (_: any, record: AutoMLData) => (
        <div>
          <Button
            type="link"
            size="small"
            key="start"
            icon={<KFIcon type="icon-yunhang" />}
            onClick={() => startAutoML(record)}
          >
            运行
          </Button>
          <Button
            type="link"
            size="small"
            key="edit"
            icon={<KFIcon type="icon-bianji" />}
            onClick={() => createAutoML(record, false)}
          >
            编辑
          </Button>
          <Button
            type="link"
            size="small"
            key="copy"
            icon={<KFIcon type="icon-fuzhi" />}
            onClick={() => createAutoML(record, true)}
          >
            复制
          </Button>

          <ConfigProvider
            theme={{
              token: {
                colorLink: themes['warningColor'],
              },
            }}
          >
            <Button
              type="link"
              size="small"
              key="remove"
              icon={<KFIcon type="icon-shanchu" />}
              onClick={() => handleAutoMLDelete(record)}
            >
              删除
            </Button>
          </ConfigProvider>
        </div>
      ),
    },
  ];

  return (
    <div className={styles['experiment-list']}>
      <PageTitle title={config.title + '实验列表'}></PageTitle>
      <div className={styles['experiment-list__content']}>
        <div className={styles['experiment-list__content__filter']}>
          <Input.Search
            placeholder="按实验名称筛选"
            onSearch={onSearch}
            onChange={(e) => setInputText(e.target.value)}
            style={{ width: 300 }}
            value={inputText}
            allowClear
          />
          <Button
            style={{ marginLeft: '20px' }}
            type="default"
            onClick={() => createAutoML()}
            icon={<KFIcon type="icon-xinjian2" />}
          >
            新建实验
          </Button>
        </div>
        <div
          className={classNames('vertical-scroll-table', styles['experiment-list__content__table'])}
        >
          <Table
            dataSource={tableData}
            columns={columns}
            scroll={{ y: 'calc(100% - 55px)' }}
            pagination={{
              ...pagination,
              total: total,
              showSizeChanger: true,
              showQuickJumper: true,
              showTotal: () => `共${total}条`,
            }}
            onChange={handleTableChange}
            expandable={{
              expandedRowRender: (record) => (
                <ExperimentInstanceList
                  type={type}
                  experimentInsList={experimentInsList}
                  experimentInsTotal={experimentInsTotal}
                  onClickInstance={(item) => gotoInstanceInfo(record, item)}
                  onRemove={() => {
                    refreshExperimentIns(record.id);
                    refreshExperimentList();
                  }}
                  onTerminate={handleInstanceTerminate}
                  onLoadMore={() => loadMoreExperimentIns()}
                ></ExperimentInstanceList>
              ),
              onExpand: handleExpandChange,
              expandedRowKeys: expandedRowKeys,
            }}
            rowKey="id"
          />
        </div>
      </div>
    </div>
  );
}

export default ExperimentList;
