/*
 * @Author: 赵伟
 * @Date: 2024-04-16 13:58:08
 * @Description: 创建服务版本
 */
import CodeSelect from '@/components/CodeSelect';
import KFIcon from '@/components/KFIcon';
import PageTitle from '@/components/PageTitle';
import ResourceSelect, {
  requiredValidator,
  ResourceSelectorType,
  type ParameterInputObject,
} from '@/components/ResourceSelect';
import SubAreaTitle from '@/components/SubAreaTitle';
import { useComputingResource } from '@/hooks/resource';
import {
  createServiceVersionReq,
  getServiceInfoReq,
  updateServiceVersionReq,
} from '@/services/modelDeployment';
import { changePropertyName } from '@/utils';
import { to } from '@/utils/promise';
import SessionStorage from '@/utils/sessionStorage';
import { modalConfirm } from '@/utils/ui';
import { PlusOutlined } from '@ant-design/icons';
import { useNavigate, useParams } from '@umijs/max';
import { App, Button, Col, Flex, Form, Input, Row, Select } from 'antd';
import { omit, pick } from 'lodash';
import { useEffect, useState } from 'react';
import {
  CreateServiceVersionFrom,
  ServiceData,
  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 }[]; // 环境变量
};

function CreateServiceVersion() {
  const navigate = useNavigate();
  const [form] = Form.useForm();
  const [resourceStandardList, filterResourceStandard] = useComputingResource();
  const [operationType, setOperationType] = useState(ServiceOperationType.Create);
  const [lastPage, setLastPage] = useState(CreateServiceVersionFrom.ServiceInfo);
  const { message } = App.useApp();
  const [serviceInfo, setServiceInfo] = useState<ServiceData | undefined>(undefined);
  const [versionInfo, setVersionInfo] = useState<ServiceVersionData | undefined>(undefined);
  const params = useParams();
  const id = params.id;

  useEffect(() => {
    const res:
      | (ServiceVersionData & {
          operationType: ServiceOperationType;
          lastPage: CreateServiceVersionFrom;
        })
      | 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);
    };
  }, []);

  useEffect(() => {
    getServiceInfo();
  }, []);

  // 获取服务详情
  const getServiceInfo = async () => {
    const [res] = await to(getServiceInfoReq(id));
    if (res && res.data) {
      setServiceInfo(res.data);
      form.setFieldsValue({
        service_name: res.data.service_name,
      });
    }
  };

  // 创建版本
  const createServiceVersion = async (formData: FormData) => {
    const envList = formData['env_variables'] ?? [];
    const image = formData['image'];
    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', 'image', 'model', 'code_config']),
      replicas: Number(formData.replicas),
      env_variables: envVariables,
      image: image.value,
      model: changePropertyName(
        pick(model, ['id', 'name', 'version', 'path', 'identifier', 'owner', 'showValue']),
        { showValue: 'show_value' },
      ),
      code_config: changePropertyName(pick(codeConfig, ['code_path', 'branch', 'showValue']), {
        showValue: 'show_value',
      }),
      service_id: serviceInfo?.id,
    };

    const params =
      operationType === ServiceOperationType.Create
        ? object
        : {
            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(`/modelDeployment/serviceInfo/${serviceInfo?.id}`, { 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}
                    size="large"
                  />
                </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}
                    size="large"
                    disabled={disabled}
                  />
                </Form.Item>
              </Col>
            </Row>
            <Row gutter={8}>
              <Col span={10}>
                <Form.Item
                  label="代码配置"
                  name="code_config"
                  rules={[
                    {
                      validator: requiredValidator,
                      message: '请选择代码配置',
                    },
                  ]}
                  required
                >
                  <CodeSelect
                    placeholder="请选择代码配置"
                    canInput={false}
                    size="large"
                    disabled={disabled}
                  />
                </Form.Item>
              </Col>
            </Row>
            <Row gutter={8}>
              <Col span={10}>
                <Form.Item
                  label="资源规格"
                  name="resource"
                  rules={[
                    {
                      required: true,
                      message: '请选择资源规格',
                    },
                  ]}
                >
                  <Select
                    showSearch
                    placeholder="请选择资源规格"
                    filterOption={filterResourceStandard}
                    options={resourceStandardList}
                    fieldNames={{
                      label: 'description',
                      value: 'standard',
                    }}
                  />
                </Form.Item>
              </Col>
            </Row>
            <Row gutter={8}>
              <Col span={10}>
                <Form.Item
                  label="副本数量"
                  name="replicas"
                  rules={[
                    {
                      required: true,
                      message: '请输入副本数量',
                    },
                    {
                      pattern: /^[1-9]\d*$/,
                      message: '副本数量必须是正整数',
                    },
                  ]}
                >
                  <Input placeholder="请输入副本数量" allowClear />
                </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>

            <Form.List name="env_variables">
              {(fields, { add, remove }) => (
                <>
                  <Row gutter={8}>
                    <Col span={10}>
                      <Form.Item label="环境变量">
                        {fields.length === 0 ? (
                          <Button
                            type="link"
                            style={{ padding: '0' }}
                            onClick={() => add()}
                            disabled={disabled}
                          >
                            添加环境变量
                          </Button>
                        ) : null}
                      </Form.Item>
                    </Col>
                  </Row>
                  {fields.map(({ key, name, ...restField }) => (
                    <Flex key={key} align="center" gap="0 8px" style={{ width: '50%' }}>
                      <Form.Item
                        {...restField}
                        name={[name, 'key']}
                        style={{ flex: 1 }}
                        rules={[
                          { required: true, message: '请输入变量名' },
                          {
                            pattern: /^[a-zA-Z_][a-zA-Z0-9_-]*$/,
                            message:
                              '变量名只支持字母、数字、下划线、中横线且开头必须是字母或下划线',
                          },
                        ]}
                      >
                        <Input placeholder="请输入变量名" disabled={disabled} />
                      </Form.Item>
                      <span style={{ marginBottom: '24px' }}>=</span>
                      <Form.Item
                        {...restField}
                        name={[name, 'value']}
                        style={{ flex: 1 }}
                        rules={[{ required: true, message: '请输入变量值' }]}
                      >
                        <Input placeholder="请输入变量值" disabled={disabled} />
                      </Form.Item>
                      <Button
                        type="link"
                        style={{ marginBottom: '24px' }}
                        icon={<KFIcon type="icon-shanchu" font={16} />}
                        disabled={disabled}
                        onClick={() => {
                          modalConfirm({
                            title: '删除',
                            content: '是否确认要删除该环境变量?',
                            onOk: () => {
                              remove(name);
                            },
                          });
                        }}
                      ></Button>
                    </Flex>
                  ))}
                  {fields.length > 0 ? (
                    <Button
                      type="link"
                      style={{ padding: '0', margin: '-24px 0 24px' }}
                      onClick={() => add()}
                      icon={<PlusOutlined />}
                      disabled={disabled}
                    >
                      环境变量
                    </Button>
                  ) : null}
                </>
              )}
            </Form.List>
            <Form.Item wrapperCol={{ offset: 0, span: 16 }}>
              <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;
