import { $t } from '#/locales';

import nodeNames from './nodeNames';

const INVALID_FILE_NAME_PATTERN = /[\\/:*?"<>|\u0000-\u001f\u007f]/g;

export const makeFileTargetFormatValues = ['md', 'html', 'pdf', 'docx'] as const;
export const makeFileSourceFormatValues = ['plain_text', 'markdown', 'html'] as const;
const DEFAULT_TARGET_FORMAT = 'docx';
const DEFAULT_SOURCE_FORMAT = 'markdown';
const DEFAULT_TEMPLATE_STYLE = 'default';

type MakeFileTargetFormat = (typeof makeFileTargetFormatValues)[number];
type MakeFileSourceFormat = (typeof makeFileSourceFormatValues)[number];

function isMakeFileTargetFormat(value: unknown): value is MakeFileTargetFormat {
  return typeof value === 'string' && makeFileTargetFormatValues.includes(value as MakeFileTargetFormat);
}

function isMakeFileSourceFormat(value: unknown): value is MakeFileSourceFormat {
  return typeof value === 'string' && makeFileSourceFormatValues.includes(value as MakeFileSourceFormat);
}

function getConfiguredTargetFormat(data?: Record<string, any>) {
  const candidate = data?.targetFormat;
  return isMakeFileTargetFormat(candidate) ? candidate : DEFAULT_TARGET_FORMAT;
}

export function sanitizeMakeFileNodeFileName(value?: string) {
  return (value ?? '').replace(INVALID_FILE_NAME_PATTERN, '').trim();
}

export function isMakeFileFormatCombinationAllowed(
  sourceFormat = DEFAULT_SOURCE_FORMAT,
  targetFormat = 'docx',
) {
  return !(
    sourceFormat === 'html' &&
    (targetFormat === 'md' || targetFormat === 'docx')
  );
}

export function resolveMakeFileNodeSourceFormat(data?: Record<string, any>): MakeFileSourceFormat {
  return isMakeFileSourceFormat(data?.sourceFormat) ? data.sourceFormat : DEFAULT_SOURCE_FORMAT;
}

export function resolveMakeFileNodeTargetFormat(data?: Record<string, any>): MakeFileTargetFormat {
  const sourceFormat = resolveMakeFileNodeSourceFormat(data);
  const targetFormat = getConfiguredTargetFormat(data);
  if (isMakeFileFormatCombinationAllowed(sourceFormat, targetFormat)) {
    return targetFormat;
  }
  return sourceFormat === 'html' ? 'html' : DEFAULT_TARGET_FORMAT;
}

export function resolveMakeFileNodeTemplateStyle(data?: Record<string, any>) {
  return data?.templateStyle === DEFAULT_TEMPLATE_STYLE ? DEFAULT_TEMPLATE_STYLE : DEFAULT_TEMPLATE_STYLE;
}

export function getMakeFileTargetFormatOptions(sourceFormat = DEFAULT_SOURCE_FORMAT) {
  return makeFileTargetFormatValues
    .filter((targetFormat) => isMakeFileFormatCombinationAllowed(sourceFormat, targetFormat))
    .map((value) => ({
      label: value,
      value,
    }));
}

export function getMakeFileNodeFormPatch(
  name: string,
  nextValue: string | number | boolean | undefined,
  data?: Record<string, any>,
) {
  if (name === 'sourceFormat') {
    const sourceFormat = isMakeFileSourceFormat(nextValue) ? nextValue : DEFAULT_SOURCE_FORMAT;
    const currentTargetFormat = getConfiguredTargetFormat(data);
    if (isMakeFileFormatCombinationAllowed(sourceFormat, currentTargetFormat)) {
      return { sourceFormat };
    }
    return {
      sourceFormat,
      targetFormat: sourceFormat === 'html' ? 'html' : DEFAULT_TARGET_FORMAT,
    };
  }

  if (name === 'targetFormat') {
    const sourceFormat = resolveMakeFileNodeSourceFormat(data);
    const targetFormat = isMakeFileTargetFormat(nextValue) ? nextValue : DEFAULT_TARGET_FORMAT;
    return {
      targetFormat: isMakeFileFormatCombinationAllowed(sourceFormat, targetFormat)
        ? targetFormat
        : sourceFormat === 'html'
          ? 'html'
          : DEFAULT_TARGET_FORMAT,
    };
  }

  if (name === 'templateStyle') {
    return { templateStyle: resolveMakeFileNodeTemplateStyle({ templateStyle: nextValue }) };
  }

  return { [name]: nextValue };
}

function handleFileNameInput(event: Event) {
  const target = event.target as HTMLInputElement | null;
  if (!target) {
    return;
  }
  const sanitized = sanitizeMakeFileNodeFileName(target.value);
  if (target.value !== sanitized) {
    target.value = sanitized;
  }
}

export default {
  [nodeNames.makeFileNode]: {
    title: $t('aiWorkflow.fileGeneration'),
    group: 'base',
    description: $t('aiWorkflow.descriptions.fileGeneration'),
    icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M14 13.5V8C14 5.79086 12.2091 4 10 4C7.79086 4 6 5.79086 6 8V13.5C6 17.0899 8.91015 20 12.5 20C16.0899 20 19 17.0899 19 13.5V4H21V13.5C21 18.1944 17.1944 22 12.5 22C7.80558 22 4 18.1944 4 13.5V8C4 4.68629 6.68629 2 10 2C13.3137 2 16 4.68629 16 8V13.5C16 15.433 14.433 17 12.5 17C10.567 17 9 15.433 9 13.5V8H11V13.5C11 14.3284 11.6716 15 12.5 15C13.3284 15 14 14.3284 14 13.5Z"></path></svg>',
    sortNo: 802,
    parametersAddEnable: false,
    outputDefsAddEnable: false,
    forms: [
      {
        type: 'heading',
        label: $t('aiWorkflow.fileSettings'),
      },
      {
        type: 'select',
        label: $t('aiWorkflow.targetFormat'),
        description: $t('aiWorkflow.descriptions.targetFormat'),
        name: 'targetFormat',
        defaultValue: DEFAULT_TARGET_FORMAT,
        resolveValue: resolveMakeFileNodeTargetFormat,
        resolveOptions: (data: Record<string, any>) =>
          getMakeFileTargetFormatOptions(resolveMakeFileNodeSourceFormat(data)),
        onValueChange: (value: string | number | boolean | undefined, data: Record<string, any>) =>
          getMakeFileNodeFormPatch('targetFormat', value, data),
      },
      {
        type: 'input',
        label: $t('aiWorkflow.fileName'),
        description: $t('aiWorkflow.descriptions.fileName'),
        name: 'fileName',
        placeholder: $t('aiWorkflow.fileNamePlaceholder'),
        attrs: {
          maxlength: 128,
          oninput: handleFileNameInput,
        },
      },
      {
        type: 'select',
        label: $t('aiWorkflow.templateStyle'),
        description: $t('aiWorkflow.descriptions.templateStyle'),
        name: 'templateStyle',
        defaultValue: DEFAULT_TEMPLATE_STYLE,
        resolveValue: resolveMakeFileNodeTemplateStyle,
        options: [
          {
            label: $t('aiWorkflow.defaultTemplateStyle'),
            value: DEFAULT_TEMPLATE_STYLE,
          },
        ],
        onValueChange: (value: string | number | boolean | undefined, data: Record<string, any>) =>
          getMakeFileNodeFormPatch('templateStyle', value, data),
      },
    ],
    parameters: [
      {
        name: 'content',
        nameDisabled: true,
        title: $t('preferences.content'),
        dataType: 'String',
        required: true,
        description: $t('preferences.content'),
        deleteDisabled: true,
      },
    ],
    outputDefs: [
      {
        name: 'url',
        nameDisabled: true,
        title: $t('aiWorkflow.fileDownloadURL'),
        dataType: 'String',
        dataTypeDisabled: true,
        required: true,
        parametersAddEnable: false,
        description: $t('aiWorkflow.descriptions.fileDownloadURL'),
        deleteDisabled: true,
      },
    ],
  },
};
