/*
 * @Author: 赵伟
 * @Date: 2024-04-16 13:58:08
 * @Description: 创建服务版本
 */
import CodeSelect from '@/components/CodeSelect';
import PageTitle from '@/components/PageTitle';
import ParameterSelect from '@/components/ParameterSelect';
import ResourceSelect, {
  ResourceSelectorType,
  requiredValidator,
  type ParameterInputObject,
} from '@/components/ResourceSelect';
import SubAreaTitle from '@/components/SubAreaTitle';
import {
  createServiceVersionReq,
  getServiceInfoReq,
  updateServiceVersionReq,
} from '@/services/modelDeployment';
import { changePropertyName } from '@/utils';
import { to } from '@/utils/promise';
import SessionStorage from '@/utils/sessionStorage';
import { removeFormListItem } from '@/utils/ui';
import { MinusCircleOutlined, PlusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { useNavigate, useParams } from '@umijs/max';
import { App, Button, Col, Flex, Form, Input, InputNumber, Row } from 'antd';
import { omit, pick } from 'lodash';
import { useEffect, useState } from 'react';
import { CreateServiceVersionFrom, ServiceOperationType, ServiceVersionData } from '../types';
import styles from './index.less';

// 表单数据
export type FormData = {
  service_name: string; // 服务名称
  version: string; // 服务版本
  description: string; // 描述
  model: ParameterInputObject; // 模型
  image: ParameterInputObject; // 镜像
  code_config: ParameterInputObject; // 代码
  resource: string; // 资源规格
  replicas: string; // 副本数量
  mount_path: string; // 模型路径
  env_variables: { key: string; value: string }[]; // 环境变量
};

type ServiceVersionCache = ServiceVersionData & {
  operationType: ServiceOperationType;
  lastPage: CreateServiceVersionFrom;
};

// 参数表单数据
export type FormEnvVariable = {
  key: string; // 参数名
  value: string; // 参数值
};

function CreateServiceVersion() {
  const navigate = useNavigate();
  const [form] = Form.useForm();

  const [operationType, setOperationType] = useState(ServiceOperationType.Create);
  const [lastPage, setLastPage] = useState(CreateServiceVersionFrom.ServiceInfo);
  const { message } = App.useApp();
  const [versionInfo, setVersionInfo] = useState<ServiceVersionData | undefined>(undefined);
  const params = useParams();
  const serviceId = params.serviceId;

  // 因为没有服务版本详情接口，需要从缓存中获取
  useEffect(() => {
    const res: ServiceVersionCache | undefined = SessionStorage.getItem(
      SessionStorage.serviceVersionInfoKey,
      true,
    );
    if (res) {
      setOperationType(res.operationType);
      setLastPage(res.lastPage);
      setVersionInfo(res);
      let model, codeConfig, envVariables;
      if (res.model && typeof res.model === 'object') {
        model = changePropertyName(res.model, { show_value: 'showValue' });
        // 接口返回是数据没有 value 值，但是 form 需要 value
        model.value = model.showValue;
      }
      if (res.code_config && typeof res.code_config === 'object') {
        codeConfig = changePropertyName(res.code_config, { show_value: 'showValue' });
        // 接口返回是数据没有 value 值，但是 form 需要 value
        codeConfig.value = codeConfig.showValue;
      }
      if (res.env_variables && typeof res.env_variables === 'object') {
        envVariables = Object.entries(res.env_variables).map(([key, value]) => ({
          key,
          value,
        }));
      }

      const formData = {
        ...omit(res, 'model', 'code_config', 'env_variables'),
        model: model,
        code_config: codeConfig,
        env_variables: envVariables,
      };
      form.setFieldsValue(formData);
    }
    return () => {
      SessionStorage.removeItem(SessionStorage.serviceVersionInfoKey);
    };
  }, [form]);

  useEffect(() => {
    // 获取服务详情，设置服务名称
    const getServiceInfo = async () => {
      const [res] = await to(getServiceInfoReq(serviceId));
      if (res && res.data) {
        form.setFieldsValue({
          service_name: res.data.service_name,
        });
      }
    };

    getServiceInfo();
  }, [serviceId, form]);

  // 创建版本
  const createServiceVersion = async (formData: FormData) => {
    const envList = formData['env_variables'];
    const model = formData['model'];
    const codeConfig = formData['code_config'];
    const envVariables = envList?.reduce((acc, cur) => {
      acc[cur.key] = cur.value;
      return acc;
    }, {} as Record<string, string>);

    // 根据后台要求，修改表单数据
    const object = {
      ...omit(formData, ['replicas', 'env_variables', 'model', 'code_config']),
      replicas: Number(formData.replicas),
      env_variables: envVariables,
      model: changePropertyName(
        pick(model, ['id', 'name', 'version', 'path', 'identifier', 'owner', 'showValue']),
        { showValue: 'show_value' },
      ),
      code_config: codeConfig
        ? changePropertyName(pick(codeConfig, ['code_path', 'branch', 'showValue']), {
            showValue: 'show_value',
          })
        : undefined,
      service_id: serviceId,
    };

    const params =
      operationType === ServiceOperationType.Create
        ? {
            ...object,
            deploy_type: 'web',
          }
        : {
            id: versionInfo?.id,
            rerun: operationType === ServiceOperationType.Restart ? true : false,
            deployment_name: versionInfo?.deployment_name,
            ...object,
          };

    const request =
      operationType === ServiceOperationType.Create
        ? createServiceVersionReq
        : updateServiceVersionReq;

    const [res] = await to(request(params));
    if (res) {
      message.success('操作成功');
      if (lastPage === CreateServiceVersionFrom.ServiceInfo) {
        navigate(-1);
      } else {
        navigate(`/dataset/modelDeployment/serviceInfo/${serviceId}`, { replace: true });
      }
    }
  };

  // 提交
  const handleSubmit = (values: FormData) => {
    createServiceVersion(values);
  };

  // 取消
  const cancel = () => {
    navigate(-1);
  };

  const disabled = operationType !== ServiceOperationType.Create;
  let buttonText = '新建';
  let title = '新增服务版本';
  if (operationType === ServiceOperationType.Update) {
    title = '更新服务版本';
    buttonText = '更新';
  } else if (operationType === ServiceOperationType.Restart) {
    title = '重启服务版本';
    buttonText = '重启';
  }

  return (
    <div className={styles['create-service-version']}>
      <PageTitle title={title}></PageTitle>
      <div className={styles['create-service-version__content']}>
        <div>
          <Form
            name="create-service-version"
            labelCol={{ flex: '100px' }}
            labelAlign="left"
            form={form}
            onFinish={handleSubmit}
            size="large"
            autoComplete="off"
          >
            <SubAreaTitle
              title="基本信息"
              image={require('@/assets/img/mirror-basic.png')}
              style={{ marginBottom: '26px' }}
            ></SubAreaTitle>
            <Row gutter={8}>
              <Col span={10}>
                <Form.Item
                  label="服务名称"
                  name="service_name"
                  rules={[
                    {
                      required: true,
                      message: '请输入服务名称',
                    },
                  ]}
                >
                  <Input
                    placeholder="请输入服务名称"
                    maxLength={30}
                    disabled
                    showCount
                    allowClear
                  />
                </Form.Item>
              </Col>
            </Row>
            <Row gutter={8}>
              <Col span={10}>
                <Form.Item
                  label="服务版本"
                  name="version"
                  rules={[
                    {
                      required: true,
                      message: '请输入服务版本',
                    },
                    {
                      pattern: /^[a-zA-Z0-9._-]+$/,
                      message: '版本只支持字母、数字、点(.)、下划线(_)、中横线(-)',
                    },
                  ]}
                >
                  <Input
                    placeholder="请输入服务版本"
                    maxLength={30}
                    disabled={disabled}
                    showCount
                    allowClear
                  />
                </Form.Item>
              </Col>
            </Row>
            <Row gutter={8}>
              <Col span={20}>
                <Form.Item
                  label="版本描述"
                  name="description"
                  rules={[
                    {
                      required: true,
                      message: '请输入版本描述',
                    },
                  ]}
                >
                  <Input.TextArea
                    autoSize={{ minRows: 2, maxRows: 6 }}
                    placeholder="请输入版本描述，最长128字符"
                    maxLength={128}
                    showCount
                    allowClear
                  />
                </Form.Item>
              </Col>
            </Row>
            <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="model"
                  rules={[
                    {
                      validator: requiredValidator,
                      message: '请选择模型',
                    },
                  ]}
                  required
                >
                  <ResourceSelect
                    type={ResourceSelectorType.Model}
                    placeholder="请选择模型"
                    disabled={disabled}
                    canInput={false}
                  />
                </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}
                    disabled={disabled}
                  />
                </Form.Item>
              </Col>
            </Row>
            <Row gutter={8}>
              <Col span={10}>
                <Form.Item label="代码配置" name="code_config">
                  <CodeSelect
                    placeholder="请选择代码配置"
                    canInput={false}
                    size="large"
                    disabled={disabled}
                  />
                </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>
            <Row gutter={8}>
              <Col span={10}>
                <Form.Item
                  label="副本数量"
                  name="replicas"
                  rules={[
                    {
                      required: true,
                      message: '请输入副本数量',
                    },
                    {
                      pattern: /^[1-9]\d*$/,
                      message: '副本数量必须是正整数',
                    },
                  ]}
                >
                  <InputNumber
                    style={{ width: '100%' }}
                    placeholder="请输入副本数量"
                    min={1}
                    precision={0}
                  />
                </Form.Item>
              </Col>
            </Row>

            <Row gutter={8}>
              <Col span={10}>
                <Form.Item
                  label="挂载路径"
                  name="mount_path"
                  rules={[
                    {
                      required: true,
                      message: '请输入模型挂载路径',
                    },
                    {
                      pattern: /^\/[a-zA-Z0-9._/-]+$/,
                      message:
                        '请输入正确的挂载路径，以斜杠(/)开头，只支持字母、数字、点(.)、下划线(_)、中横线(-)、斜杠(/)',
                    },
                  ]}
                >
                  <Input
                    placeholder="请输入模型挂载路径"
                    disabled={disabled}
                    maxLength={64}
                    showCount
                    allowClear
                  />
                </Form.Item>
              </Col>
            </Row>

            <Row gutter={8}>
              <Col span={10}>
                <Form.Item label="环境变量">
                  <Form.List name="env_variables">
                    {(fields, { add, remove }) => (
                      <>
                        {fields.map(({ key, name, ...restField }, index) => (
                          <Flex
                            key={key}
                            gap="0 8px"
                            style={{
                              position: 'relative',
                            }}
                          >
                            <Form.Item
                              {...restField}
                              name={[name, 'key']}
                              style={{ flex: 1 }}
                              rules={[
                                {
                                  validator: (_, value) => {
                                    if (!value) {
                                      return Promise.reject(new Error('请输入变量名'));
                                    }
                                    if (!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(value)) {
                                      return Promise.reject(
                                        new Error(
                                          '变量名只支持字母、数字、下划线、中横线并且必须以字母或下划线开头',
                                        ),
                                      );
                                    }
                                    // 判断不能重名
                                    const list = form
                                      .getFieldValue('env_variables')
                                      .filter(
                                        (item: FormEnvVariable | undefined) =>
                                          item !== undefined && item !== null,
                                      );

                                    const names = list.map((item: FormEnvVariable) => item.key);
                                    if (new Set(names).size !== names.length) {
                                      return Promise.reject(new Error('名称不能重复'));
                                    }
                                    return Promise.resolve();
                                  },
                                },
                              ]}
                            >
                              <Input placeholder="请输入变量名" disabled={disabled} allowClear />
                            </Form.Item>
                            <span style={{ lineHeight: '46px' }}>=</span>
                            <Form.Item
                              {...restField}
                              name={[name, 'value']}
                              style={{ flex: 1 }}
                              rules={[{ required: true, message: '请输入变量值' }]}
                            >
                              <Input placeholder="请输入变量值" disabled={disabled} allowClear />
                            </Form.Item>
                            <Flex
                              style={{
                                width: '76px',
                                left: 'calc(100% + 10px)',
                                height: '46px',
                                marginBottom: '24px',
                                position: 'absolute',
                              }}
                              align="center"
                            >
                              <Button
                                style={{
                                  marginRight: '3px',
                                }}
                                shape="circle"
                                size="middle"
                                type="text"
                                icon={<MinusCircleOutlined />}
                                disabled={disabled}
                                onClick={() => {
                                  removeFormListItem(
                                    form,
                                    'env_variables',
                                    name,
                                    remove,
                                    ['key', 'value'],
                                    '删除后，该环境变量将不可恢复',
                                  );
                                }}
                              ></Button>
                              {index === fields.length - 1 && (
                                <Button
                                  shape="circle"
                                  size="middle"
                                  type="text"
                                  disabled={disabled}
                                  icon={<PlusCircleOutlined />}
                                  onClick={() => add()}
                                ></Button>
                              )}
                            </Flex>
                          </Flex>
                        ))}
                        {fields.length === 0 && (
                          <Form.Item className={styles['create-service-version__content__env']}>
                            <Button
                              className={styles['create-service-version__content__env__add-btn']}
                              color="primary"
                              variant="dashed"
                              disabled={disabled}
                              icon={<PlusOutlined />}
                              block
                              onClick={() => add()}
                            >
                              环境变量
                            </Button>
                          </Form.Item>
                        )}
                      </>
                    )}
                  </Form.List>
                </Form.Item>
              </Col>
            </Row>

            <Form.Item wrapperCol={{ offset: 0, span: 16 }} style={{ marginTop: '20px' }}>
              <Button type="primary" htmlType="submit">
                {buttonText}
              </Button>
              <Button
                type="default"
                htmlType="button"
                onClick={cancel}
                style={{ marginLeft: '20px' }}
              >
                取消
              </Button>
            </Form.Item>
          </Form>
        </div>
      </div>
    </div>
  );
}

export default CreateServiceVersion;
