import KFIcon from '@/components/KFIcon';
import { ExperimentStatus, TensorBoardStatus } from '@/enums';
import {
  deleteExperimentById,
  getExperiment,
  getExperimentById,
  getQueryByExperimentId,
  getTensorBoardStatusReq,
  postExperiment,
  putExperiment,
  runExperiments,
  runTensorBoardReq,
} from '@/services/experiment/index.js';
import { getWorkflow } from '@/services/pipeline/index.js';
import themes from '@/styles/theme.less';
import { to } from '@/utils/promise';
import tableCellRender, { TableCellValueType } from '@/utils/table';
import { modalConfirm } from '@/utils/ui';
import { App, Button, ConfigProvider, Dropdown, Space, Table } from 'antd';
import classNames from 'classnames';
import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { ComparisonType } from './Comparison/config';
import AddExperimentModal from './components/AddExperimentModal';
import ExperimentInstance from './components/ExperimentInstance';
import Styles from './index.less';
import { experimentStatusInfo } from './status';

// 定时器
const timerIds = new Map();

function Experiment() {
  const navigate = useNavigate();
  const [experimentList, setExperimentList] = useState([]);
  const [workflowList, setWorkflowList] = useState([]);
  const [queryFlow, setQueryFlow] = useState({
    offset: 1,
    page: 0,
    size: 10000,
    name: null,
  });
  const [experimentId, setExperimentId] = useState(null);
  const [experimentInList, setExperimentInList] = useState([]);
  const [expandedRowKeys, setExpandedRowKeys] = useState(null);
  const [total, setTotal] = useState(0);
  const [isAdd, setIsAdd] = useState(true);
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [addFormData, setAddFormData] = useState({});
  const [experimentInsTotal, setExperimentInsTotal] = useState(0);
  const { message } = App.useApp();
  const pageOption = useRef({ page: 1, size: 10 });
  const paginationProps = {
    showSizeChanger: true,
    showQuickJumper: true,
    showTotal: () => `共${total}条`,
    total: total,
    page: pageOption.current.page,
    size: pageOption.current.size,
    onChange: (current, size) => paginationChange(current, size),
  };

  useEffect(() => {
    getExperimentList();
    getWorkflowList();
    return () => {
      clearExperimentInTimers();
    };
  }, []);

  // 获取实验列表
  const getExperimentList = async () => {
    const params = {
      offset: 0,
      page: pageOption.current.page - 1,
      size: pageOption.current.size,
    };
    const [res] = await to(getExperiment(params));
    if (res && res.data && Array.isArray(res.data.content)) {
      setExperimentList(
        res.data.content.map((item) => {
          return { ...item, key: item.id };
        }),
      );

      setTotal(res.data.totalElements);
    }
  };

  // 获取流水线列表
  const getWorkflowList = async () => {
    const [res] = await to(getWorkflow(queryFlow));
    if (res && res.data && res.data.content) {
      setWorkflowList(res.data.content);
    }
  };

  // 获取实验实例列表
  const getQueryByExperiment = async (experimentId, page) => {
    const params = {
      experimentId: experimentId,
      page: page,
      size: 5,
    };
    const [res, error] = await to(getQueryByExperimentId(params));
    if (res && res.data) {
      const { content = [], totalElements = 0 } = res.data;
      setExpandedRowKeys(experimentId);
      try {
        const list = content.map((v) => {
          const nodes_result = v.nodes_result ? JSON.parse(v.nodes_result) : {};
          return {
            ...v,
            nodes_result,
          };
        });
        if (page === 0) {
          setExperimentInList(list);
          clearExperimentInTimers();
        } else {
          setExperimentInList((prev) => [...prev, ...list]);
        }
        setExperimentInsTotal(totalElements);
        // 获取 TensorBoard 状态
        list.forEach((item) => {
          if (item.nodes_result?.tensorboard_log) {
            getTensorBoardStatus(item);
          }
        });
      } catch (error) {
        console.error('JSON parse error: ', error);
      }
    }
  };

  // 运行 TensorBoard
  const runTensorBoard = async (experimentIn) => {
    const params = {
      namespace: experimentIn.nodes_result.tensorboard_log.namespace,
      path: experimentIn.nodes_result.tensorboard_log.path,
      pvc_name: experimentIn.nodes_result.tensorboard_log.pvc_name,
    };
    const [res] = await to(runTensorBoardReq(params));
    if (res) {
      experimentIn.tensorboardUrl = res.data;
      const timerId = timerIds.get(experimentIn.id);
      if (timerId) {
        clearTimeout(timerId);
        timerIds.delete(experimentIn.id);
        getTensorBoardStatus(experimentIn);
      }
    }
  };

  // 获取 TensorBoard 状态
  const getTensorBoardStatus = async (experimentIn) => {
    const params = {
      namespace: experimentIn.nodes_result.tensorboard_log.namespace,
      path: experimentIn.nodes_result.tensorboard_log.path,
      pvc_name: experimentIn.nodes_result.tensorboard_log.pvc_name,
    };
    const [res] = await to(getTensorBoardStatusReq(params));
    if (res && res.data) {
      setExperimentInList((prevList) => {
        return prevList.map((item) => {
          if (item.id === experimentIn.id) {
            return {
              ...item,
              tensorBoardStatus: res.data.status,
              tensorboardUrl: res.data.url,
            };
          }
          return item;
        });
      });

      let timerId = timerIds.get(experimentIn.id);
      if (timerId) {
        clearTimeout(timerId);
        timerIds.delete(experimentIn.id);
      }
      timerId = setTimeout(() => {
        getTensorBoardStatus(experimentIn);
      }, 10 * 1000);
      timerIds.set(experimentIn.id, timerId);
    }
  };

  // 展开实例
  const expandChange = (e, record) => {
    clearExperimentInTimers();
    setExperimentInList([]);
    if (record.id === expandedRowKeys) {
      setExpandedRowKeys(null);
    } else {
      getQueryByExperiment(record.id, 0);
    }
  };

  // 终止实验实例获取 TensorBoard 状态的定时器
  const clearExperimentInTimers = () => {
    timerIds.values().forEach((timerId) => {
      clearTimeout(timerId);
    });
    timerIds.clear();
  };

  // 创建实验
  const createExperiment = () => {
    setIsAdd(true);
    setAddFormData({});
    setExperimentId(null);
    setIsModalOpen(true);
  };

  // 编辑实验
  const editExperiment = (id) => {
    getExperimentById(id).then((res) => {
      setAddFormData({
        ...res.data,
      });
      setExperimentId(res.data.id);
      setIsAdd(false);
      setIsModalOpen(true);
    });
  };
  // 创建或编辑实验取消
  const handleCancel = () => {
    setIsModalOpen(false);
  };

  // 创建或者编辑实验
  const handleAddExperiment = async (values, isRun) => {
    const global_param = JSON.stringify(values.global_param);
    if (!experimentId) {
      const params = {
        ...values,
        global_param,
      };
      const [res] = await to(postExperiment(params));
      if (res) {
        message.success('新建实验成功');
        setIsModalOpen(false);
        getExperimentList();
      }
    } else {
      const params = { ...values, global_param, id: experimentId };
      const [res] = await to(putExperiment(params));
      if (res) {
        message.success('编辑实验成功');
        setIsModalOpen(false);
        getExperimentList();

        // 确定并运行
        if (isRun) {
          runExperiment(experimentId);
        }
      }
    }
  };

  // 当前页面切换
  const paginationChange = async (current, size) => {
    pageOption.current = {
      page: current,
      size: size,
    };
    getExperimentList();
  };
  // 运行实验
  const runExperiment = async (id) => {
    const [res] = await to(runExperiments(id));
    if (res) {
      message.success('运行成功');
      refreshExperimentIns(id);
    } else {
      message.error('运行失败');
    }
  };

  // 跳转到流水线
  const gotoPipeline = (record) => {
    navigate({ pathname: `/pipeline/template/info/${record.workflow_id}` });
  };

  // 跳转到实验实例详情
  const gotoInstanceInfo = (item, record) => {
    navigate({ pathname: `/pipeline/experiment/instance/${record.workflow_id}/${item.id}` });
  };

  // 处理 TensorBoard 操作
  const handleTensorboard = async (experimentIn) => {
    if (
      experimentIn.tensorBoardStatus === TensorBoardStatus.Terminated ||
      experimentIn.tensorBoardStatus === TensorBoardStatus.Failed
    ) {
      await runTensorBoard(experimentIn);
    } else if (
      experimentIn.tensorBoardStatus === TensorBoardStatus.Running &&
      experimentIn.tensorboardUrl
    ) {
      window.open(experimentIn.tensorboardUrl, '_blank');
    }
  };

  // 刷新实验列表状态，
  // 目前是直接刷新实验列表，后续需要优化，只刷新状态
  const refreshExperimentList = () => {
    getExperimentList();
  };

  // 实验实例终止
  const handleInstanceTerminate = async (experimentIn) => {
    // 刷新实验列表
    refreshExperimentList();
    setExperimentInList((prevList) => {
      return prevList.map((item) => {
        if (item.id === experimentIn.id) {
          return {
            ...item,
            status: ExperimentStatus.Terminated,
          };
        }
        return item;
      });
    });
  };

  // 实验对比菜单
  const getComparisonMenu = (experimentId) => {
    return {
      items: [
        {
          label: <span>训练对比</span>,
          key: ComparisonType.Train,
        },
        {
          label: <span>评估对比</span>,
          key: ComparisonType.Evaluate,
        },
      ],
      onClick: ({ key }) => {
        navigate(`/pipeline/experiment/compare?type=${key}&id=${experimentId}`);
      },
    };
  };

  // 刷新实验实例列表
  const refreshExperimentIns = (experimentId) => {
    getQueryByExperiment(experimentId, 0);
  };

  // 加载更多实验实例
  const loadMoreExperimentIns = () => {
    const page = Math.round(experimentInList.length / 5);
    getQueryByExperiment(expandedRowKeys, page);
  };

  const columns = [
    {
      title: '实验名称',
      dataIndex: 'name',
      key: 'name',
      render: tableCellRender(),
      width: '16%',
    },
    {
      title: '关联流水线名称',
      dataIndex: 'workflow_name',
      key: 'workflow_name',
      render: tableCellRender(false, TableCellValueType.Link, {
        onClick: gotoPipeline,
      }),
      width: '16%',
    },
    {
      title: '实验描述',
      dataIndex: 'description',
      key: 'description',
      render: tableCellRender(true),
      ellipsis: { showTitle: false },
    },
    {
      title: '最近五次运行状态',
      dataIndex: 'status_list',
      key: 'status_list',
      width: 200,
      render: (text) => {
        let newText = text && text.replace(/\s+/g, '').split(',');
        return (
          <>
            {newText && newText.length > 0
              ? newText.map((item, index) => {
                  return (
                    <img
                      style={{ width: '17px', marginRight: '6px' }}
                      key={index}
                      src={experimentStatusInfo[item].icon}
                      draggable={false}
                      alt=""
                    />
                  );
                })
              : null}
          </>
        );
      },
    },
    {
      title: '操作',
      key: 'action',
      width: 360,
      render: (_, record) => (
        <Space size="small">
          <Button
            type="link"
            size="small"
            key="run"
            icon={<KFIcon type="icon-yunhang" />}
            onClick={() => {
              runExperiment(record.id);
            }}
          >
            运行
          </Button>
          <Button
            type="link"
            size="small"
            key="edit"
            icon={<KFIcon type="icon-bianji" />}
            onClick={() => {
              editExperiment(record.id);
            }}
          >
            编辑
          </Button>
          <Dropdown key="comparison" menu={getComparisonMenu(record.id)}>
            <a onClick={(e) => e.preventDefault()}>
              <Space style={{ padding: '0 7px' }}>
                <KFIcon type="icon-shiyanduibi" />
                实验对比
              </Space>
            </a>
          </Dropdown>
          <ConfigProvider
            theme={{
              token: {
                colorLink: themes['warningColor'],
              },
            }}
          >
            <Button
              type="link"
              size="small"
              key="batchRemove"
              icon={<KFIcon type="icon-shanchu" />}
              onClick={() => {
                modalConfirm({
                  title: '删除后，该实验将不可恢复',
                  content: '是否确认删除?',
                  onOk: () => {
                    deleteExperimentById(record.id).then((ret) => {
                      if (ret.code === 200) {
                        message.success('删除成功');
                        getExperimentList();
                      } else {
                        message.error(ret.msg);
                      }
                    });
                  },
                });
              }}
            >
              删除
            </Button>
          </ConfigProvider>
        </Space>
      ),
    },
  ];
  return (
    <div className={Styles.experimentBox}>
      <div className={Styles.experimentTopBox}>
        <Button type="default" onClick={createExperiment} icon={<KFIcon type="icon-xinjian2" />}>
          新建实验
        </Button>
      </div>
      <div className={classNames('vertical-scroll-table', Styles.experimentTable)}>
        <Table
          columns={columns}
          dataSource={experimentList}
          pagination={paginationProps}
          rowKey="id"
          scroll={{ y: 'calc(100% - 55px)' }}
          expandable={{
            expandedRowRender: (record) => (
              <ExperimentInstance
                experimentInList={experimentInList}
                experimentInsTotal={experimentInsTotal}
                onClickInstance={(item) => gotoInstanceInfo(item, record)}
                onClickTensorBoard={handleTensorboard}
                onRemove={() => {
                  refreshExperimentIns(record.id);
                  refreshExperimentList();
                }}
                onTerminate={handleInstanceTerminate}
                onLoadMore={() => loadMoreExperimentIns()}
              ></ExperimentInstance>
            ),
            onExpand: (e, a) => {
              expandChange(e, a);
            },
            expandedRowKeys: [expandedRowKeys],
            rowExpandable: (record) => true,
          }}
        />
      </div>

      {isModalOpen && (
        <AddExperimentModal
          isAdd={isAdd}
          open={isModalOpen}
          initialValues={addFormData}
          onCancel={handleCancel}
          onFinish={handleAddExperiment}
          workflowList={workflowList}
        />
      )}
    </div>
  );
}
export default Experiment;
