import CodeSelect from '@/components/CodeSelect';
import KFIcon from '@/components/KFIcon';
import ParameterSelect from '@/components/ParameterSelect';
import ResourceSelect, {
  ResourceSelectorType,
  requiredValidator,
} from '@/components/ResourceSelect';
import SubAreaTitle from '@/components/SubAreaTitle';
import { hyperParameterOptimizedModeOptions } from '@/enums';
import { isEmpty } from '@/utils';
import { modalConfirm, removeFormListItem } from '@/utils/ui';
import { MinusCircleOutlined, PlusCircleOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import {
  Button,
  Col,
  Flex,
  Form,
  Input,
  InputNumber,
  Radio,
  Row,
  Select,
  Tooltip,
  Typography,
} from 'antd';
import { isEqual } from 'lodash';
import PopParameterRange from './PopParameterRange';
import styles from './index.less';
import {
  axParameterOptions,
  parameterOptions,
  schedulerAlgorithms,
  searchAlgorithms,
  type FormParameter,
} from './utils';

const parameterTooltip = `uniform(low, high)
    在 low 和 high 之间均匀采样浮点数

    quniform(low, high, q)
    在 low 和 high 之间均匀采样浮点数，四舍五入到 q 的倍数
    
    loguniform(low, high)
    在 low 和 high 之间均匀采样浮点数，对数空间采样
    
    qloguniform(low, high, q)
    在 low 和 high 之间均匀采样浮点数，对数空间采样并四舍五入到 q 的倍数
    
    randn(m, s)
    在均值为 m，方差为 s 的正态分布中进行随机浮点数抽样
    
    qrandn(m, s, q)
    在均值为 m，方差为 s 的正态分布中进行随机浮点数抽样，四舍五入到 q 的倍数
    
    randint(low, high)
    在 low（包括）到 high（不包括）之间均匀采样整数
    
    qrandint(low, high, q)
    在 low（包括）到 high（不包括）之间均匀采样整数，四舍五入到 q 的倍数（包括 high）
    
    lograndint(low, high)
    在 low（包括）到 high（不包括）之间对数空间上均匀采样整数
   
    qlograndint(low, high, q)
    在 low（包括）到 high（不包括）之间对数空间上均匀采样整数,并四舍五入到 q 的倍数
    
    choice
    从指定的选项中采样一个选项
    
    grid
    对选项进行网格搜索，每个值都将被采样
`;

const axParameterTooltip = `fixed
    固定取值

    range(low, high)
    在 low 和 high 范围内采样取值
    
    choice
    从指定的选项中采样一个选项
  `;

function ExecuteConfig() {
  const form = Form.useFormInstance();
  const searchAlgorithm = Form.useWatch('search_alg', form);
  const paramsTypeOptions = searchAlgorithm === 'Ax' ? axParameterOptions : parameterOptions;
  const paramsTypeTooltip = searchAlgorithm === 'Ax' ? axParameterTooltip : parameterTooltip;

  const handleSearchAlgorithmChange = (value: string) => {
    if (
      (value === 'Ax' && searchAlgorithm !== 'Ax') ||
      (value !== 'Ax' && searchAlgorithm === 'Ax')
    ) {
      form.setFieldValue('parameters', [{ name: '' }]);
    }
  };

  return (
    <>
      <SubAreaTitle
        title="配置信息"
        image={require('@/assets/img/model-deployment.png')}
        style={{ marginTop: '20px', marginBottom: '24px' }}
      ></SubAreaTitle>

      <Row gutter={8}>
        <Col span={10}>
          <Form.Item
            label="代码配置"
            name="code_config"
            rules={[
              {
                validator: requiredValidator,
                message: '请选择代码配置',
              },
            ]}
            required
          >
            <CodeSelect placeholder="请选择代码配置" canInput={false} size="large" />
          </Form.Item>
        </Col>
      </Row>

      <Row gutter={8}>
        <Col span={10}>
          <Form.Item
            label="主函数代码文件"
            name="main_py"
            rules={[
              {
                required: true,
                message: '请输入主函数代码文件',
              },
            ]}
          >
            <Input placeholder="请输入主函数代码文件" maxLength={64} showCount allowClear />
          </Form.Item>
        </Col>
      </Row>

      <Row gutter={8}>
        <Col span={10}>
          <Form.Item
            label="镜像"
            name="image"
            rules={[
              {
                validator: requiredValidator,
                message: '请选择镜像',
              },
            ]}
            required
          >
            <ResourceSelect
              type={ResourceSelectorType.Mirror}
              placeholder="请选择镜像"
              canInput={false}
            />
          </Form.Item>
        </Col>
      </Row>

      <Row gutter={8}>
        <Col span={10}>
          <Form.Item
            label="数据集"
            name="dataset"
            rules={[
              {
                validator: requiredValidator,
                message: '请选择数据集',
              },
            ]}
            required
          >
            <ResourceSelect
              type={ResourceSelectorType.Dataset}
              placeholder="请选择数据集"
              canInput={false}
            />
          </Form.Item>
        </Col>
      </Row>

      <Row gutter={8}>
        <Col span={10}>
          <Form.Item label="模型" name="model">
            <ResourceSelect
              type={ResourceSelectorType.Model}
              placeholder="请选择模型"
              canInput={false}
            />
          </Form.Item>
        </Col>
      </Row>

      <Row gutter={8}>
        <Col span={10}>
          <Form.Item
            label="总试验次数"
            name="num_samples"
            rules={[
              {
                required: true,
                message: '请输入总试验次数',
              },
            ]}
          >
            <InputNumber placeholder="请输入总试验次数" min={0} precision={0} />
          </Form.Item>
        </Col>
      </Row>

      <Row gutter={8}>
        <Col span={10}>
          <Form.Item label="搜索算法" name="search_alg">
            <Select
              placeholder="请选择搜索算法"
              options={searchAlgorithms}
              showSearch
              allowClear
              onChange={handleSearchAlgorithmChange}
            />
          </Form.Item>
        </Col>
      </Row>

      <Row gutter={8}>
        <Col span={10}>
          <Form.Item label="调度算法" name="scheduler">
            <Select
              placeholder="请选择调度算法"
              options={schedulerAlgorithms}
              showSearch
              allowClear
            />
          </Form.Item>
        </Col>
      </Row>

      <Form.Item dependencies={['scheduler']} noStyle>
        {({ getFieldValue }) => {
          const schedulerAlgorithm = getFieldValue('scheduler');
          if (schedulerAlgorithm === 'ASHA' || schedulerAlgorithm === 'HyperBand') {
            return (
              <Row gutter={8}>
                <Col span={10}>
                  <Form.Item
                    label="单次试验最大时间"
                    name="max_t"
                    tooltip="每次试验的最大时间单位，单位秒"
                    rules={[
                      {
                        required: true,
                        message: '单次试验最大时间',
                      },
                    ]}
                  >
                    <InputNumber placeholder="请输入单次试验最大时间" min={0} precision={0} />
                  </Form.Item>
                </Col>
              </Row>
            );
          } else if (schedulerAlgorithm === 'MedianStopping') {
            return (
              <Row gutter={8}>
                <Col span={10}>
                  <Form.Item
                    label="最小试验数"
                    name="min_samples_required"
                    tooltip="计算中位数的最小试验数"
                    rules={[
                      {
                        required: true,
                        message: '请输入计算中位数的最小试验数',
                      },
                    ]}
                  >
                    <InputNumber placeholder="请输入计算中位数的最小试验数" min={0} precision={0} />
                  </Form.Item>
                </Col>
              </Row>
            );
          }
          return null;
        }}
      </Form.Item>

      <Form.List name="parameters">
        {(fields, { add, remove }) => (
          <>
            <Row gutter={8}>
              <Col span={10}>
                <Form.Item
                  label="超参数"
                  style={{ marginBottom: 0, marginTop: '-14px' }}
                  required
                ></Form.Item>
              </Col>
            </Row>
            <div className={styles['hyper-parameter']}>
              <Flex align="center" className={styles['hyper-parameter__header']}>
                <div className={styles['hyper-parameter__header__name']}>参数名称</div>
                <div className={styles['hyper-parameter__header__type']}>
                  参数类型
                  <Tooltip
                    title={paramsTypeTooltip}
                    placement="top"
                    arrow={{ pointAtCenter: true }}
                    overlayClassName={styles['hyper-parameter__header__tooltip']}
                  >
                    <QuestionCircleOutlined />
                  </Tooltip>
                </div>
                <div className={styles['hyper-parameter__header__space']}>取值范围</div>
                <div className={styles['hyper-parameter__header__operation']}>操作</div>
              </Flex>

              {fields.map(({ key, name, ...restField }, index) => (
                <Flex key={key} align="flex-start" className={styles['hyper-parameter__body']}>
                  <Form.Item
                    className={styles['hyper-parameter__body__name']}
                    {...restField}
                    name={[name, 'name']}
                    required
                    rules={[
                      {
                        validator: (_, value) => {
                          if (!value) {
                            return Promise.reject(new Error('请输入参数名称'));
                          }
                          // 判断不能重名
                          const list = form
                            .getFieldValue('parameters')
                            .filter(
                              (item: FormParameter | undefined) =>
                                item !== undefined && item !== null,
                            );

                          const names = list.map((item: FormParameter) => item.name);
                          if (new Set(names).size !== names.length) {
                            return Promise.reject(new Error('名称不能重复'));
                          }
                          return Promise.resolve();
                        },
                      },
                    ]}
                  >
                    <Input placeholder="请输入参数名称" maxLength={64} showCount allowClear />
                  </Form.Item>
                  <Form.Item
                    className={styles['hyper-parameter__body__name']}
                    {...restField}
                    name={[name, 'type']}
                    rules={[{ required: true, message: '请选择参数类型' }]}
                  >
                    <Select
                      placeholder="请选择参数类型"
                      options={paramsTypeOptions}
                      onChange={() => {
                        form.setFieldValue(['parameters', name, 'range'], undefined);
                      }}
                      showSearch
                      allowClear
                    />
                  </Form.Item>
                  <Form.Item dependencies={[['parameters', name, 'type']]} noStyle>
                    {({ getFieldValue }) => {
                      const type = getFieldValue(['parameters', name, 'type']);
                      return (
                        <Form.Item
                          className={styles['hyper-parameter__body__name']}
                          {...restField}
                          name={[name, 'range']}
                          rules={[{ required: true, message: '请输入取值范围' }]}
                        >
                          <PopParameterRange type={type}></PopParameterRange>
                        </Form.Item>
                      );
                    }}
                  </Form.Item>

                  <div className={styles['hyper-parameter__body__operation']}>
                    <Button
                      style={{
                        marginRight: '3px',
                      }}
                      shape="circle"
                      disabled={fields.length === 1}
                      type="text"
                      size="middle"
                      icon={<MinusCircleOutlined />}
                      onClick={() => {
                        removeFormListItem(
                          form,
                          'parameters',
                          name,
                          remove,
                          ['name', 'type'],
                          '删除后，该参数将不可恢复',
                        );
                      }}
                    ></Button>
                    {index === fields.length - 1 && (
                      <Button
                        shape="circle"
                        size="middle"
                        type="text"
                        onClick={() => add()}
                        icon={<PlusCircleOutlined />}
                      ></Button>
                    )}
                  </div>
                </Flex>
              ))}
              {fields.length === 0 && (
                <div className={styles['hyper-parameter__add']}>
                  <Button type="link" onClick={() => add()} icon={<KFIcon type="icon-xinjian2" />}>
                    添加一行
                  </Button>
                </div>
              )}
            </div>
          </>
        )}
      </Form.List>

      <Form.Item
        noStyle
        shouldUpdate={(prevValues, curValues) =>
          !isEqual(prevValues.parameters, curValues.parameters)
        }
      >
        {({ getFieldValue }) => {
          const parameters = getFieldValue('parameters').filter(
            (item: FormParameter | undefined) => item !== undefined && item !== null && item.name,
          );
          if (parameters.length === 0) {
            return null;
          }

          return (
            <Form.List
              name="points_to_evaluate"
              rules={[
                {
                  validator: (_, runParameters) => {
                    const parameters = form
                      .getFieldValue('parameters')
                      .filter(
                        (item: FormParameter | undefined) => item !== undefined && item !== null,
                      );
                    for (const item of parameters) {
                      const name = item?.name;
                      const arr = runParameters.filter((item?: Record<string, any>) =>
                        isEmpty(item?.[name]),
                      );
                      if (arr.length > 0 && arr.length < runParameters.length) {
                        return Promise.reject(
                          new Error(`手动运行超参数 "${name}" 必须全部填写或者都不填写`),
                        );
                      }
                    }

                    return Promise.resolve();
                  },
                },
              ]}
            >
              {(fields, { add, remove }, { errors }) => (
                <>
                  <Row gutter={8}>
                    <Col span={10}>
                      <Form.Item
                        label="手动运行超参数"
                        style={{ marginBottom: 0, marginTop: '-14px' }}
                      ></Form.Item>
                    </Col>
                  </Row>
                  <div className={styles['run-parameter']}>
                    {fields.map(({ key, name, ...restField }, index) => (
                      <Flex key={key} align="center" style={{ marginBottom: '20px' }}>
                        <div className={styles['run-parameter__body']}>
                          {parameters.map((item: FormParameter) => (
                            <Form.Item
                              key={item.name}
                              label={
                                <Typography.Text ellipsis={{ tooltip: item.name }}>
                                  {item.name}
                                </Typography.Text>
                              }
                              {...restField}
                              labelCol={{ flex: '140px' }}
                              name={[name, item.name]}
                              preserve={false}
                            >
                              <Input
                                placeholder="请输入"
                                maxLength={64}
                                showCount
                                allowClear
                                onChange={() => form.validateFields(['points_to_evaluate'])}
                              />
                            </Form.Item>
                          ))}
                        </div>
                        <div className={styles['run-parameter__operation']}>
                          <Button
                            style={{
                              marginRight: '3px',
                            }}
                            shape="circle"
                            type="text"
                            size="middle"
                            icon={<MinusCircleOutlined />}
                            onClick={() => {
                              modalConfirm({
                                title: '删除后，该运行参数将不可恢复',
                                content: '是否确认删除?',
                                onOk: () => {
                                  remove(name);
                                },
                              });
                            }}
                          ></Button>
                          {index === fields.length - 1 && (
                            <Button
                              shape="circle"
                              size="middle"
                              type="text"
                              onClick={() => add()}
                              icon={<PlusCircleOutlined />}
                            ></Button>
                          )}
                        </div>
                      </Flex>
                    ))}
                    {fields.length === 0 && (
                      <Form.Item className={styles['add-weight']}>
                        <Button
                          className={styles['add-weight__button']}
                          color="primary"
                          variant="dashed"
                          onClick={() => add()}
                          block
                          icon={<PlusCircleOutlined />}
                        >
                          添加手动运行参数
                        </Button>
                      </Form.Item>
                    )}
                    <Form.ErrorList errors={errors} className={styles['run-parameter__error']} />
                  </div>
                </>
              )}
            </Form.List>
          );
        }}
      </Form.Item>

      <Row gutter={8}>
        <Col span={10}>
          <Form.Item
            label="指标"
            name="metric"
            rules={[
              {
                required: true,
                message: '请输入指标内容',
              },
            ]}
          >
            <Input placeholder="请输入指标内容" maxLength={64} showCount allowClear />
          </Form.Item>
        </Col>
      </Row>

      <Row gutter={0}>
        <Col span={24}>
          <Form.Item
            label="指标优化方向"
            name="mode"
            rules={[{ required: true, message: '请选择指标优化方向' }]}
          >
            <Radio.Group options={hyperParameterOptimizedModeOptions}></Radio.Group>
          </Form.Item>
        </Col>
      </Row>

      <Row gutter={8}>
        <Col span={10}>
          <Form.Item
            label="资源规格"
            name="computing_resource_id"
            rules={[
              {
                required: true,
                message: '请选择资源规格',
              },
            ]}
          >
            <ParameterSelect dataType="resource" placeholder="请选择资源规格" />
          </Form.Item>
        </Col>
      </Row>
    </>
  );
}

export default ExecuteConfig;
