import {
  alcoholAnalysisReport,
  back,
  edge,
  end,
  healthAnalysis,
  healthAnalysisReport,
  healthAnalysisScheme,
  ID_Analysis_Health,
  ID_Analysis_Pulse,
  ID_Analysis_TongueAndFace,
  ID_Back,
  ID_End,
  ID_Register,
  ID_Report_Alcohol,
  ID_Report_Health,
  ID_Report_Pulse,
  ID_Report_TongueAndFace,
  ID_Scheme_Health,
  ID_Start,
  pulseAnalysis,
  pulseAnalysisReport,
  register,
  start,
  tongueAndFaceAnalysis,
  tongueAndFaceAnalysisReport,
} from './nodes/config';
import type { LogicFlowGraphData } from '@/libs/logic-flow';

const nodeRef = {
  [ID_Start]: 'screen',
  [ID_End]: 'screen',
  [ID_Register]: /* 建档页 */ 'patient_file',
  [ID_Analysis_Pulse]: /* 脉诊页 */ 'pulse_upload',
  [ID_Analysis_TongueAndFace]: /*拍照页*/ 'tongueface_upload',
  [ID_Analysis_Health]: /* 问诊页 */ 'tongueface_analysis',
  [ID_Report_Pulse]: /* 脉诊结果页 */ 'pulse_upload_result',
  [ID_Report_TongueAndFace]:  /* 舌面诊分析报告页 */'tongueface_analysis_result',
  [ID_Report_Health]: /* 健康报告页 */ 'health_analysis',
  [ID_Scheme_Health]: /* 调理方案页 */ 'health_analysis_scheme',
  [ID_Report_Alcohol]: /* 酒精结果页 */ 'alcohol_upload_result',
} as const;

export type NodeId = keyof typeof nodeRef;
export type Gather = { level: number; sourceNodeId: NodeId; targetNodeId: NodeId | typeof ID_Back; edgeId: string }[];

const refNode = ((ref) => Object.keys(ref).reduce((record, key) => ((record[ref[<NodeId>key]] = <NodeId>key), record), {} as Record<string, NodeId>))(nodeRef);

export function toFlowRequestData(gather: Gather, data: Record<string, any>) {
  const value: string[] = [];
  for (let i = 0; i < gather.length; i++) {
    const { targetNodeId } = gather[i];
    if (targetNodeId === ID_Back && i !== gather.length - 1) {
      value.push(value.pop()!.replace(/\?*$/, '?'));
    } else if (targetNodeId !== ID_Back && targetNodeId !== ID_End) value.push(nodeRef[targetNodeId]);
  }
  const getReportRequestData = (key: string) => data[key]?.elements ?? [];
  return {
    tabletProcessModules: value,
    tabletFileFields: data[ID_Register] ?? [],
    tabletRequiredPageOperationElements: [
      ...getReportRequestData(ID_Report_TongueAndFace),
      ...getReportRequestData(ID_Report_Health),
      ...getReportRequestData(ID_Scheme_Health),
    ] as string[],
    ...(data[ID_Start] as {
      partner: string;
      technicalSupporter: string;
      tabletDrainageImage: string;
    }),
    timestamp: Date.now(),
  } as const;
}

export type FlowRequestData = Partial<ReturnType<typeof toFlowRequestData>>;

type ReportPrefixKey = 'tongueface_upload_report_page' | 'health_analysis_report_page' | 'health_analysis_scheme_page';

export const Preset_Image_1 = `preset:1;el:btn;`;
export const Preset_Image_2 = `preset:2;el:scan;`;

export function fromFlowRequestData(data?: FlowRequestData) {
  const getReportRequestData = (key: ReportPrefixKey) => ({
    key,
    elements: Array.isArray(data?.tabletRequiredPageOperationElements) ? data.tabletRequiredPageOperationElements.filter((item) => item.startsWith(key)) : [],
  });

  const group = [
    [register({ requestData: Array.isArray(data?.tabletFileFields) ? data.tabletFileFields : [] })],
    [pulseAnalysis(), pulseAnalysisReport()],
    [tongueAndFaceAnalysis(), tongueAndFaceAnalysisReport({ requestData: getReportRequestData('tongueface_upload_report_page') })],
    [healthAnalysis()],
    [alcoholAnalysisReport()],
    [
      healthAnalysisReport({ requestData: getReportRequestData('health_analysis_report_page') }),
      healthAnalysisScheme({ requestData: getReportRequestData('health_analysis_scheme_page') }),
    ],
    [back()],
  ];

  const nodes = new Set<string>([ID_Start, ID_End]);
  const edges: LogicFlowGraphData['edges'] = [];
  const flow = Array.isArray(data?.tabletProcessModules) ? [...data.tabletProcessModules] : [];
  if (flow.length && flow[0] === nodeRef[ID_Start]) flow.shift();
  if (flow.length && flow[flow.length - 1] === nodeRef[ID_End]) flow.pop();
  flow.unshift(ID_Start);
  flow.push(ID_End);
  for (let i = 1; i < flow.length; i++) {
    const [source] = flow[i - 1].split(/[?:]/).filter(Boolean);
    const [target, title, countDown] = flow[i].split(/[?:]/).filter(Boolean);
    const optional = flow[i].includes('?');

    const sourceNodeId = refNode[source] ?? source;
    const targetNodeId = refNode[target] ?? target;

    nodes.add(sourceNodeId).add(targetNodeId);

    edges.push(edge(sourceNodeId, targetNodeId));
    if (optional) edges.push(edge(sourceNodeId, ID_Back, { title, countDown }));
  }
  if (edges.some(edge => edge.targetNodeId === ID_Back)) nodes.add(ID_Back);
  return {
    graph: {
      nodes: Array.from(nodes, (id) => {
        if (id === ID_Start)
          return start({
            requestData: {
              partner: data?.partner,
              technicalSupporter: data?.technicalSupporter,
              tabletDrainageImage: data?.tabletDrainageImage || Preset_Image_1,
            },
          });
        if (id === ID_End) return end();
        for (const items of group) for (const node of items) if (node.id == id) return node;
        return void 0;
      }).filter(Boolean),
      edges,
    } as LogicFlowGraphData,
    group,
  };
}

export const Field_Card = 'cardno';
export const Field_Phone = 'phone';
export function analysisRegisterFields(fields?: string[]) {
  const config = [
    [Field_Card, '身份证号', true],
    [Field_Phone, '手机号码', true],
    ['name', '姓名'],
    ['age', '年龄'],
    ['sex', '性别'],
    ['height', '身高'],
    ['weight', '体重'],
    ['womenSpecialPeriod', '女性特殊期'],
    ['isEasyAllergy', '容易过敏'],
    ['foodAllergy', '食物过敏'],
    ['hobbyFlavor', '喜好口味'],
    ['drinkState', '饮酒情况'],
    ['smokeState', '吸烟情况'],
    ['address', '现住址'],
    ['detailAddress', '详细地址'],
    ['job', '职业'],
  ] as const;

  if (!Array.isArray(fields)) fields = [];
  type Option = { id: string; name: string; required?: boolean };
  const options: Option[] = config.map(([id, name, required = false]) => ({ id, name, required }));
  const selected: Option[] = [];
  for (const item of fields) {
    const [id, required] = item.split(':');
    if (id === 'code') continue;
    const index = options.findIndex((item) => item.id === id);
    if (index > -1) selected.push({ ...options.splice(index, 1)[0], required: required === 'required' || required === 'true' });
  }

  return { config, options, selected };
}

export const Key_miniProgramCode = 'appletbutton';
export const Key_payLock = 'appletscan';
export const Key_jumpable = 'notjump';
export const Key_printable = 'notprint';

export function analysisRequestData(data?: FlowRequestData): Record<
  NodeId,
  {
    has: boolean;
    optional: boolean;
    format: string;
    fields?: { id: string; name: string; required?: boolean }[];
    payLock?: boolean;
    miniProgramCode?: boolean;
    jumpable?: boolean;
    printable?: boolean;
  }
> {
  const get = (id: NodeId) => {
    const key = data?.tabletProcessModules?.find((key) => key.startsWith(nodeRef[id])) ?? '';
    const has = !!key;
    const optional = key.includes('?');
    return { has, optional, format: has ? `有${optional ? '(可选)' : ''}` : '无' };
  };

  const report = (id: NodeId, prefix: ReportPrefixKey) => {
    const values = get(id);
    if (values.has) {
      const payLock = data?.tabletRequiredPageOperationElements?.includes(`${prefix}_${Key_payLock}`);
      const mini = data?.tabletRequiredPageOperationElements?.includes(`${prefix}_${Key_miniProgramCode}`);
      values.format += `(${mini && payLock ? '扫码查看' : '完整展示'})`;
      Object.assign(values, { payLock: mini && payLock, miniProgramCode: mini });
      if (id === ID_Report_Health) {
        const jumpable = !data?.tabletRequiredPageOperationElements?.includes(`${prefix}_${Key_jumpable}`);
        const printable = !data?.tabletRequiredPageOperationElements?.includes(`${prefix}_${Key_printable}`);
        Object.assign(values, { jumpable, printable });
      }
    }
    return values;
  };

  return {
    [ID_Register]: {
      ...get(ID_Register),
      fields: analysisRegisterFields(data?.tabletFileFields).selected,
    },
    [ID_Analysis_Pulse]: get(ID_Analysis_Pulse),
    [ID_Analysis_TongueAndFace]: get(ID_Analysis_TongueAndFace),
    [ID_Analysis_Health]: get(ID_Analysis_Health),
    [ID_Report_Pulse]: get(ID_Report_Pulse),
    [ID_Report_TongueAndFace]: report(ID_Report_TongueAndFace, 'tongueface_upload_report_page'),
    [ID_Report_Alcohol]: get(ID_Report_Alcohol),
    [ID_Report_Health]: report(ID_Report_Health, 'health_analysis_report_page'),
    [ID_Scheme_Health]: report(ID_Scheme_Health, 'health_analysis_scheme_page'),
  } as any;
}
