import CodeSelectorModal from '@/components/CodeSelectorModal';
import KFIcon from '@/components/KFIcon';
import ParameterInput, { requiredValidator } from '@/components/ParameterInput';
import ParameterSelect, { type ParameterSelectDataType } from '@/components/ParameterSelect';
import ResourceSelectorModal, {
  ResourceSelectorType,
  selectorTypeConfig,
} from '@/components/ResourceSelectorModal';
import SubAreaTitle from '@/components/SubAreaTitle';
import { CommonTabKeys } from '@/enums';
import { canInput, createMenuItems } from '@/pages/Pipeline/Info/utils';
import {
  PipelineGlobalParam,
  PipelineNodeModel,
  PipelineNodeModelParameter,
  PipelineNodeModelSerialize,
} from '@/types';
import { openAntdModal } from '@/utils/modal';
import { to } from '@/utils/promise';
import { INode } from '@antv/g6';
import { Button, Drawer, Form, Input, MenuProps } from 'antd';
import { RuleObject } from 'antd/es/form';
import { NamePath } from 'antd/es/form/interface';
import { forwardRef, useImperativeHandle, useState } from 'react';
import PropsLabel from '../PropsLabel';
import styles from './index.less';
const { TextArea } = Input;

type PipelineNodeParameterProps = {
  onFormChange: (data: PipelineNodeModelSerialize) => void;
};

const PipelineNodeParameter = forwardRef(({ onFormChange }: PipelineNodeParameterProps, ref) => {
  const [form] = Form.useForm();
  const [stagingItem, setStagingItem] = useState<PipelineNodeModelSerialize>(
    {} as PipelineNodeModelSerialize,
  );
  const [open, setOpen] = useState(false);
  const [menuItems, setMenuItems] = useState<MenuProps['items']>([]);

  const afterOpenChange = async () => {
    if (!open) {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const [_values, error] = await to(form.validateFields());
      // 不管是否验证成功，都需要获取表单数据
      const fields = form.getFieldsValue();

      // 保存字段顺序
      const control_strategy = {
        ...stagingItem.control_strategy,
        ...fields.control_strategy,
      };
      const in_parameters = {
        ...stagingItem.in_parameters,
        ...fields.in_parameters,
      };
      const out_parameters = {
        ...stagingItem.out_parameters,
        ...fields.out_parameters,
      };

      // console.log('getFieldsValue', fields);

      const res = {
        ...stagingItem,
        ...fields,
        control_strategy: JSON.stringify(control_strategy),
        in_parameters: JSON.stringify(in_parameters),
        out_parameters: JSON.stringify(out_parameters),
        formError: !!error,
      };
      // console.log('res', res);
      onFormChange(res);
    }
  };
  const onClose = () => {
    setOpen(false);
  };

  useImperativeHandle(
    ref,
    () => ({
      showDrawer(
        model: PipelineNodeModel,
        params: PipelineGlobalParam[],
        parentNodes: INode[],
        validate: boolean = false,
      ) {
        try {
          const nodeData: PipelineNodeModelSerialize = {
            ...model,
            in_parameters: JSON.parse(model.in_parameters),
            out_parameters: JSON.parse(model.out_parameters),
            control_strategy: JSON.parse(model.control_strategy),
          };
          // console.log('model', nodeData);
          setStagingItem({
            ...nodeData,
          });
          form.resetFields();
          form.setFieldsValue({
            ...nodeData,
          });
          if (validate) {
            form.validateFields();
          }
        } catch (error) {
          console.error('JSON.parse error: ', error);
        }
        setOpen(true);

        // 参数下拉菜单
        setMenuItems(createMenuItems(params, parentNodes));
      },
      close: () => {
        onClose();
      },
      validateFields: async () => {
        if (!open) {
          return;
        }
        const [values, error] = await to(form.validateFields());
        if (!error && values) {
          return values;
        } else {
          form.scrollToField((error as any)?.errorFields?.[0]?.name, { block: 'center' });
          return Promise.reject(error);
        }
      },
    }),
    [form, open],
  );

  // ref 类型选择
  const selectRefData = (
    formItemName: NamePath,
    item: PipelineNodeModelParameter | Pick<PipelineNodeModelParameter, 'item_type'>,
  ) => {
    if (item.item_type === 'code') {
      selectCodeConfig(formItemName, item);
    } else {
      selectResource(formItemName, item);
    }
  };

  // 选择代码配置
  const selectCodeConfig = (
    formItemName: NamePath,
    item: PipelineNodeModelParameter | Pick<PipelineNodeModelParameter, 'item_type'>,
  ) => {
    const { close } = openAntdModal(CodeSelectorModal, {
      onOk: (res) => {
        if (res) {
          const { id, code_repo_name, git_url, git_branch, git_user_name, git_password, ssh_key } =
            res;
          const value = JSON.stringify({
            id,
            name: code_repo_name,
            code_path: git_url,
            branch: git_branch,
            username: git_user_name,
            password: git_password,
            ssh_private_key: ssh_key,
          });
          form.setFieldValue(formItemName, {
            ...item,
            value,
            showValue: code_repo_name,
            fromSelect: true,
          });
          form.validateFields([formItemName]);
        }
        close();
      },
    });
  };

  // 选择数据集、模型、镜像
  const selectResource = (
    formItemName: NamePath,
    item: PipelineNodeModelParameter | Pick<PipelineNodeModelParameter, 'item_type'>,
  ) => {
    let type: ResourceSelectorType;
    switch (item.item_type) {
      case 'dataset':
        type = ResourceSelectorType.Dataset;
        break;
      case 'model':
        type = ResourceSelectorType.Model;
        break;
      default:
        type = ResourceSelectorType.Mirror;
        break;
    }
    const fieldValue = form.getFieldValue(formItemName);
    const activeTab = fieldValue?.activeTab as CommonTabKeys | undefined;
    const expandedKeys = Array.isArray(fieldValue?.expandedKeys) ? fieldValue?.expandedKeys : [];
    const checkedKeys = Array.isArray(fieldValue?.checkedKeys) ? fieldValue?.checkedKeys : [];
    const { close } = openAntdModal(ResourceSelectorModal, {
      type,
      defaultExpandedKeys: expandedKeys,
      defaultCheckedKeys: checkedKeys,
      defaultActiveTab: activeTab,
      onOk: (res) => {
        if (res) {
          if (type === ResourceSelectorType.Mirror) {
            const { activeTab, id, version, path } = res;
            if (formItemName === 'image') {
              // 单独的选择镜像
              form.setFieldValue(formItemName, path);
            } else {
              // 输入参数选择镜像
              form.setFieldValue(formItemName, {
                ...item,
                value: path,
                showValue: path,
                fromSelect: true,
                activeTab,
                expandedKeys: [id],
                checkedKeys: [`${id}-${version}`],
              });
            }
          } else {
            const { activeTab, id, name, version, path, identifier, owner } = res;
            const value = JSON.stringify({
              id,
              name,
              version,
              path,
              identifier,
              owner,
            });
            const showValue = `${name}:${version}`;
            form.setFieldValue(formItemName, {
              ...item,
              value,
              showValue,
              fromSelect: true,
              activeTab,
              expandedKeys: [id],
              checkedKeys: [`${id}-${version}`],
            });
          }
        } else {
          if (type === ResourceSelectorType.Mirror && formItemName === 'image') {
            form.setFieldValue(formItemName, undefined);
          } else {
            form.setFieldValue(formItemName, {
              ...item,
              value: undefined,
              showValue: undefined,
              fromSelect: false,
              activeTab: undefined,
              expandedKeys: [],
              checkedKeys: [],
            });
          }
        }
        form.validateFields([formItemName]);
        close();
      },
    });
  };

  // 获取选择数据集、模型后面按钮 icon
  const getSelectBtnIcon = (item: { item_type: string }) => {
    const type = item.item_type;
    if (type === 'code') {
      return <KFIcon type="icon-xuanzedaimapeizhi" />;
    }

    let selectorType: ResourceSelectorType;
    if (type === 'dataset') {
      selectorType = ResourceSelectorType.Dataset;
    } else if (type === 'model') {
      selectorType = ResourceSelectorType.Model;
    } else {
      selectorType = ResourceSelectorType.Mirror;
    }

    return <KFIcon type={selectorTypeConfig[selectorType].buttonIcon} />;
  };

  // 参数回填
  const handleParameterClick = (name: NamePath, value: any) => {
    form.setFieldValue(name, value);
    form.validateFields([name]);
  };

  // form item label
  const getLabel = (
    item: { key: string; value: PipelineNodeModelParameter },
    namePrefix: string,
  ) => {
    return item.value.type === 'select' ? (
      item.value.label + '(' + item.key + ')'
    ) : (
      <PropsLabel
        menuItems={menuItems}
        title={item.value.label + '(' + item.key + ')'}
        onClick={(value) => {
          handleParameterClick([namePrefix, item.key], {
            ...item.value,
            value,
            fromSelect: true,
            showValue: value,
          });
        }}
      />
    );
  };

  // 模型部署-服务版本验证
  const serviceVersionValidator = (_rule: RuleObject, value: any) => {
    // 输入参数值都是对象，如果是手动输入，要求 /^[a-zA-Z0-9._-]+$/
    if (
      typeof value === 'object' &&
      value &&
      !value.fromSelect &&
      value.value &&
      !/^[a-zA-Z0-9._-]+$/.test(value.value)
    ) {
      return Promise.reject('服务版本只支持字母、数字、点(.)、下划线(_)、中横线(-)');
    }

    return Promise.resolve();
  };

  // 必填项校验规则
  const getFormRules = (item: { key: string; value: PipelineNodeModelParameter }) => {
    const id = form.getFieldValue('id') as string;
    const rules = item.value.require
      ? [
          {
            validator: requiredValidator,
          },
        ]
      : [];

    // 模型部署-服务版本验证
    if (id.startsWith('model-deploy') && item.key === '--version') {
      rules.push({
        validator: serviceVersionValidator,
      });
    }

    return rules;
  };

  // 控制策略
  const controlStrategyList = Object.entries(stagingItem.control_strategy ?? {}).map(
    ([key, value]) => ({ key, value }),
  );

  // 输入参数
  const inParametersList = Object.entries(stagingItem.in_parameters ?? {}).map(([key, value]) => ({
    key,
    value,
  }));

  // 输出参数
  const outParametersList = Object.entries(stagingItem.out_parameters ?? {}).map(
    ([key, value]) => ({ key, value }),
  );

  return (
    <Drawer
      title="编辑任务"
      placement="right"
      rootStyle={{ marginTop: '55px' }}
      getContainer={false}
      closeIcon={false}
      onClose={onClose}
      afterOpenChange={afterOpenChange}
      open={open}
      width={520}
      className={styles['pipeline-drawer']}
    >
      <Form
        name="form"
        form={form}
        layout="vertical"
        labelCol={{
          span: 24,
        }}
        wrapperCol={{
          span: 24,
        }}
        style={{
          maxWidth: 600,
        }}
        autoComplete="off"
        scrollToFirstError
      >
        <div className={styles['pipeline-drawer__title']}>
          <SubAreaTitle
            image={require('@/assets/img/static-message.png')}
            title="基本信息"
          ></SubAreaTitle>
        </div>
        <Form.Item
          label="任务名称"
          name="label"
          rules={[
            {
              required: true,
              message: '请输入任务名称',
            },
          ]}
        >
          <Input placeholder="请输入任务名称" allowClear />
        </Form.Item>
        <Form.Item
          label="任务ID"
          name="id"
          rules={[
            {
              required: true,
              message: '请输入任务id',
            },
          ]}
        >
          <Input disabled />
        </Form.Item>
        <div className={styles['pipeline-drawer__title']}>
          <SubAreaTitle
            image={require('@/assets/img/duty-message.png')}
            title="任务信息"
          ></SubAreaTitle>
        </div>
        <Form.Item label="镜像" required>
          <div className={styles['pipeline-drawer__ref-row']}>
            <Form.Item name="image" noStyle rules={[{ required: true, message: '请输入镜像' }]}>
              <Input placeholder="请输入或选择镜像" allowClear />
            </Form.Item>
            <Form.Item noStyle>
              <Button
                type="link"
                size="small"
                icon={getSelectBtnIcon({ item_type: 'image' })}
                onClick={() => selectResource('image', { item_type: 'image' })}
                className={styles['pipeline-drawer__ref-row__select-button']}
              >
                选择镜像
              </Button>
            </Form.Item>
          </div>
        </Form.Item>
        <Form.Item
          name="working_directory"
          label={
            <PropsLabel
              menuItems={menuItems}
              title="工作目录"
              onClick={(value) => {
                handleParameterClick('working_directory', value);
              }}
            />
          }
        >
          <Input placeholder="请输入工作目录" allowClear />
        </Form.Item>
        <Form.Item
          name="command"
          label={
            <PropsLabel
              menuItems={menuItems}
              title="启动命令"
              onClick={(value) => {
                handleParameterClick('command', value);
              }}
            />
          }
        >
          <TextArea placeholder="请输入启动命令" allowClear />
        </Form.Item>
        <Form.Item
          label="资源规格"
          name="resources_standard"
          rules={[
            {
              required: true,
              message: '请选择资源规格',
            },
          ]}
        >
          <ParameterSelect dataType="resource" placeholder="请选择资源规格" />
        </Form.Item>
        <Form.Item
          name="mount_path"
          label={
            <PropsLabel
              menuItems={menuItems}
              title="挂载路径"
              onClick={(value) => {
                handleParameterClick('mount_path', value);
              }}
            />
          }
        >
          <Input placeholder="请输入挂载路径" allowClear />
        </Form.Item>
        <Form.Item
          name="env_variables"
          label={
            <PropsLabel
              menuItems={menuItems}
              title="环境变量"
              onClick={(value) => {
                handleParameterClick('env_variables', value);
              }}
            />
          }
        >
          <TextArea placeholder="请输入环境变量" allowClear />
        </Form.Item>
        {/* 控制参数 */}
        {controlStrategyList.map((item) => (
          <Form.Item
            key={item.key}
            name={['control_strategy', item.key]}
            required={item.value.require ? true : false}
            label={getLabel(item, 'control_strategy')}
            rules={getFormRules(item)}
          >
            <ParameterInput placeholder={item.value.placeholder} allowClear></ParameterInput>
          </Form.Item>
        ))}
        {/* 输入参数 */}
        {inParametersList.length > 0 && (
          <>
            <div className={styles['pipeline-drawer__title']}>
              <SubAreaTitle
                image={require('@/assets/img/duty-message.png')}
                title="输入参数"
              ></SubAreaTitle>
            </div>
            {inParametersList.map((item) => (
              <Form.Item
                key={item.key}
                label={getLabel(item, 'in_parameters')}
                required={item.value.require ? true : false}
              >
                <div className={styles['pipeline-drawer__ref-row']}>
                  <Form.Item name={['in_parameters', item.key]} rules={getFormRules(item)} noStyle>
                    {item.value.type === 'select' ? (
                      ['dataset', 'model', 'service', 'resource'].includes(item.value.item_type) ? (
                        <ParameterSelect
                          isPipeline
                          dataType={item.value.item_type as ParameterSelectDataType}
                          placeholder={item.value.placeholder}
                        />
                      ) : null
                    ) : (
                      <ParameterInput
                        canInput={canInput(item.value)}
                        placeholder={item.value.placeholder}
                        allowClear
                      ></ParameterInput>
                    )}
                  </Form.Item>
                  {item.value.type === 'ref' && (
                    <Form.Item noStyle>
                      <Button
                        size="small"
                        type="link"
                        icon={getSelectBtnIcon(item.value)}
                        onClick={() => selectRefData(['in_parameters', item.key], item.value)}
                        className={styles['pipeline-drawer__ref-row__select-button']}
                      >
                        {item.value.label}
                      </Button>
                    </Form.Item>
                  )}
                </div>
              </Form.Item>
            ))}
          </>
        )}
        {/* 输出参数 */}
        {outParametersList.length > 0 && (
          <>
            <div className={styles['pipeline-drawer__title']}>
              <SubAreaTitle
                image={require('@/assets/img/duty-message.png')}
                title="输出参数"
              ></SubAreaTitle>
            </div>
            {outParametersList.map((item) => (
              <Form.Item
                key={item.key}
                name={['out_parameters', item.key]}
                required={item.value.require ? true : false}
                label={getLabel(item, 'out_parameters')}
                rules={getFormRules(item)}
              >
                <ParameterInput placeholder={item.value.placeholder} allowClear></ParameterInput>
              </Form.Item>
            ))}
          </>
        )}
      </Form>
    </Drawer>
  );
});

export default PipelineNodeParameter;
