import type { DataSchema, DataSourceFieldType, DataSourceSchema } from '@tmagic/core';
import { type CascaderOption, type FormConfig, type TabConfig } from '@tmagic/form';
import { dataSourceTemplateRegExp, getKeysArray, isNumber } from '@tmagic/utils';

import BaseFormConfig from './formConfigs/base';
import HttpFormConfig from './formConfigs/http';

const dataSourceFormConfig: TabConfig = {
  type: 'tab',
  items: [
    {
      title: '数据定义',
      status: 'fields',
      items: [
        {
          name: 'fields',
          type: 'data-source-fields',
          defaultValue: () => [],
        },
      ],
    },
    {
      title: '方法定义',
      status: 'methods',
      items: [
        {
          name: 'methods',
          type: 'data-source-methods',
          defaultValue: () => [],
        },
      ],
    },
    {
      title: '事件配置',
      items: [
        {
          name: 'events',
          src: 'datasource',
          type: 'event-select',
        },
      ],
    },
    {
      title: 'mock数据',
      items: [
        {
          name: 'mocks',
          type: 'data-source-mocks',
          defaultValue: () => [],
        },
      ],
    },
    {
      title: '请求参数裁剪',
      display: (_formState, { model }) => model.type === 'http',
      items: [
        {
          name: 'beforeRequest',
          type: 'vs-code',
          parse: true,
          autosize: { minRows: 10, maxRows: 30 },
        },
      ],
    },
    {
      title: '响应数据裁剪',
      display: (_formStat, { model }) => model.type === 'http',
      items: [
        {
          name: 'afterResponse',
          type: 'vs-code',
          parse: true,
          autosize: { minRows: 10, maxRows: 30 },
        },
      ],
    },
  ],
};

const fillConfig = <T = never>(config: FormConfig<T>): FormConfig<T> => [
  ...BaseFormConfig(),
  ...config,
  dataSourceFormConfig,
];

export const getFormConfig = (type: string, configs: Record<string, FormConfig>): FormConfig => {
  switch (type) {
    case 'base':
      return fillConfig([]);
    case 'http':
      return fillConfig(HttpFormConfig);
    default:
      return fillConfig(configs[type] || []);
  }
};

export const getFormValue = (type: string, values: Partial<DataSourceSchema>): Partial<DataSourceSchema> => {
  if (type !== 'http') {
    return values;
  }

  return {
    beforeRequest: `(options, context) => {
  /**
   * 用户可以直接编写函数，在原始接口调用之前，会运行该函数，将这个函数的返回值作为该数据源接口的入参
   *
   * options: HttpOptions
   *
   * interface HttpOptions {
   *  // 请求链接
   *  url: string;
   *  // query参数
   *  params?: Record<string, string>;
   *  // body数据
   *  data?: Record<string, any>;
   *  // 请求头
   *  headers?: Record<string, string>;
   *  // 请求方法 GET/POST
   *  method?: Method;
   * }
   *
   * context：上下文对象
   *
   * interface Content {
   *  app: TMagicApp;
   *  dataSource: HttpDataSource;
   * }
   *
   * return: HttpOptions
   */

  // 此处的返回值会作为这个接口的入参
  return options;
}`,
    afterResponse: `(response, context) => {
  /**
   * 用户可以直接编写函数，在原始接口返回之后，会运行该函数，将这个函数的返回值作为该数据源接口的返回

    * context：上下文对象
    *
    * interface Content {
    *  app: TMagicApp;
    *  dataSource: HttpDataSource;
    * }
    *
    */

  // 此处的返回值会作为这个接口的返回值
  return response;
}`,
    ...values,
  };
};

export const getDisplayField = (dataSources: DataSourceSchema[], key: string) => {
  const displayState: { value: string; type: 'var' | 'text' }[] = [];

  // 匹配es6字符串模块
  const matches = key.matchAll(dataSourceTemplateRegExp);
  let index = 0;
  for (const match of matches) {
    if (typeof match.index === 'undefined') break;

    // 字符串常量
    displayState.push({
      type: 'text',
      value: key.substring(index, match.index),
    });

    let dsText = '';
    let ds: DataSourceSchema | undefined;
    let fields: DataSchema[] | undefined;
    // 将模块解析成数据源对应的值
    getKeysArray(match[1]).forEach((item, index) => {
      if (index === 0) {
        ds = dataSources.find((ds) => ds.id === item);
        dsText += ds?.title || item;
        fields = ds?.fields;
        return;
      }

      if (isNumber(item)) {
        dsText += `[${item}]`;
      } else {
        const field = fields?.find((field) => field.name === item);
        fields = field?.fields;
        dsText += `.${field?.title || item}`;
      }
    });

    displayState.push({
      type: 'var',
      value: dsText,
    });

    index = match.index + match[0].length;
  }

  if (index < key.length) {
    displayState.push({
      type: 'text',
      value: key.substring(index),
    });
  }

  return displayState;
};

export const getCascaderOptionsFromFields = (
  fields: DataSchema[] = [],
  dataSourceFieldType: DataSourceFieldType[] = ['any'],
): CascaderOption[] => {
  const typeSet = new Set(dataSourceFieldType.length ? dataSourceFieldType : ['any']);
  const includesAny = typeSet.has('any');

  const result: CascaderOption[] = [];

  for (const field of fields) {
    const fieldType = field.type || 'any';
    const isContainerType = fieldType === 'any' || fieldType === 'array' || fieldType === 'object';

    const children = isContainerType ? getCascaderOptionsFromFields(field.fields, dataSourceFieldType) : [];

    const matchesType = includesAny || typeSet.has(fieldType);

    if (matchesType || (isContainerType && children.length)) {
      result.push({
        label: `${field.title || field.name}(${field.type})`,
        value: field.name,
        children,
      });
    }
  }

  return result;
};

export const getFieldType = (ds: DataSourceSchema | undefined, fieldNames: string[]) => {
  let fields = ds?.fields;
  let type = '';

  for (const fieldName of fieldNames) {
    if (!fields?.length) return '';

    const field = fields.find((f) => f.name === fieldName);
    if (!field) return '';

    type = field.type || '';
    fields = field.fields;
  }

  return type;
};
