import { humanId } from 'human-id';
import { isEqual } from 'lodash';

import {
  ICompilationTemplate,
  ICompilationTemplateBuiltin,
  ICompilationTemplateGroup,
  ICompilationTemplateRaptorConfig,
  ICompilationTemplateSection,
} from '@/interfaces/database/compilation-template';
import { ICompilationTemplateConfigRequest } from '@/interfaces/request/compilation-template';

import { CompilationTemplateKind } from '@/constants/compilation';

import { FormSchemaType, TemplateSchemaType } from './schema';
import {
  DefaultFieldKeys,
  DefaultTemplateValues,
  FieldKeyOrders,
  SectionPriority,
} from './constant';

export const splitExampleToBlueprintFields = (
  example: string,
): { instruction: string; page_example: string } => {
  const trimmed = example.trim();
  const separatorIndex = trimmed.indexOf('\n\n');
  if (separatorIndex === -1) {
    return { instruction: trimmed, page_example: '' };
  }
  return {
    instruction: trimmed.slice(0, separatorIndex).trim(),
    page_example: trimmed.slice(separatorIndex + 2).trim(),
  };
};

export const getFieldKeyOrder = (keys: string[]): string[] => {
  const sortedKeys = [...keys].sort();
  return (
    FieldKeyOrders.find((order) => isEqual([...order].sort(), sortedKeys)) ??
    keys
  );
};

export const generateTemplateName = () =>
  humanId({ separator: ' ', capitalize: true });

export const isConfigMetaKey = (key: string) =>
  [
    'kind',
    'llm_id',
    'global_rules',
    'example',
    'instruction',
    'page_example',
    'synthesis',
    'use_blueprint',
    'rechunk',
    'rechunk_rules',
  ].includes(key);

export const createEmptyField = (keys: string[]) =>
  Object.fromEntries(keys.map((key) => [key, '']));

export const normalizeSection = (
  section?: ICompilationTemplateSection,
): ICompilationTemplateSection => {
  const fields = section?.fields ?? [];
  return {
    description: section?.description ?? '',
    fields:
      fields.length > 0
        ? fields.map((field) =>
            Object.fromEntries(
              Object.entries(field).map(([key, value]) => [key, value ?? '']),
            ),
          )
        : [createEmptyField(DefaultFieldKeys)],
  };
};

export const buildConfigFromBuiltin = (
  builtinTemplate: ICompilationTemplateBuiltin,
  kind: string,
  llmId: string,
): TemplateSchemaType['config'] => {
  const example =
    typeof builtinTemplate.config?.example === 'string'
      ? builtinTemplate.config.example
      : '';
  const sections: TemplateSchemaType['config'] = {
    kind,
    llm_id: llmId,
    global_rules:
      typeof builtinTemplate.config?.global_rules === 'string'
        ? builtinTemplate.config.global_rules
        : '',
    example:
      typeof builtinTemplate.config?.example === 'string'
        ? builtinTemplate.config.example
        : '',
    ...(typeof builtinTemplate.config?.synthesis === 'object' &&
    builtinTemplate.config?.synthesis !== null
      ? {
          synthesis: builtinTemplate.config
            .synthesis as TemplateSchemaType['config']['synthesis'],
        }
      : {}),
    use_blueprint:
      kind === CompilationTemplateKind.Artifacts && example.length > 0,
    ...(kind !== CompilationTemplateKind.Tree
      ? {
          rechunk: builtinTemplate.config?.rechunk === true,
          rechunk_rules:
            typeof builtinTemplate.config?.rechunk_rules === 'string'
              ? builtinTemplate.config.rechunk_rules
              : '',
        }
      : {}),
  };

  if (kind === CompilationTemplateKind.Artifacts && example.length > 0) {
    const { instruction, page_example } =
      splitExampleToBlueprintFields(example);
    sections.instruction = instruction;
    sections.page_example = page_example;
  }

  if (kind === CompilationTemplateKind.Tree) {
    const builtinRaptor: ICompilationTemplateRaptorConfig =
      builtinTemplate.config?.raptor ?? {};
    return {
      ...sections,
      raptor: {
        prompt: builtinRaptor.prompt ?? '',
        max_token: builtinRaptor.max_token ?? 512,
        threshold: builtinRaptor.threshold ?? 0.1,
        rechunk: builtinRaptor.rechunk ?? false,
      },
    };
  }

  Object.entries(builtinTemplate.config ?? {}).forEach(([key, value]) => {
    if (isConfigMetaKey(key)) return;
    sections[key] = normalizeSection(
      value as ICompilationTemplateSection,
    ) as TemplateSchemaType['config'][string];
  });

  return sections;
};

export const transformDetailToForm = (
  detail: ICompilationTemplate,
): TemplateSchemaType => {
  const config = detail.config ?? {};
  const example = typeof config.example === 'string' ? config.example : '';
  const base: TemplateSchemaType['config'] = {
    kind: config.kind ?? '',
    llm_id: config.llm_id ?? '',
    global_rules: config.global_rules ?? '',
    example: typeof config.example === 'string' ? config.example : '',
    ...(typeof config.synthesis === 'object' && config.synthesis !== null
      ? {
          synthesis:
            config.synthesis as TemplateSchemaType['config']['synthesis'],
        }
      : {}),
    use_blueprint:
      detail.kind === CompilationTemplateKind.Artifacts && example.length > 0,
    ...(detail.kind !== CompilationTemplateKind.Tree
      ? {
          rechunk: config.rechunk === true,
          rechunk_rules:
            typeof config.rechunk_rules === 'string'
              ? config.rechunk_rules
              : '',
        }
      : {}),
  };

  if (detail.kind === CompilationTemplateKind.Artifacts && example.length > 0) {
    const { instruction, page_example } =
      splitExampleToBlueprintFields(example);
    base.instruction = instruction;
    base.page_example = page_example;
  }

  if (detail.kind === CompilationTemplateKind.Tree) {
    const raptor: ICompilationTemplateRaptorConfig = config.raptor ?? {};
    return {
      id: detail.id,
      name: detail.name ?? '',
      description: detail.description ?? '',
      llm_id: config.llm_id ?? '',
      kind: detail.kind ?? '',
      config: {
        ...base,
        raptor: {
          prompt: raptor.prompt ?? '',
          max_token: raptor.max_token ?? 512,
          threshold: raptor.threshold ?? 0.1,
          rechunk: raptor.rechunk ?? false,
        },
      },
    };
  }

  Object.entries(config).forEach(([key, value]) => {
    if (isConfigMetaKey(key)) return;
    base[key] = normalizeSection(
      value as ICompilationTemplateSection,
    ) as TemplateSchemaType['config'][string];
  });

  return {
    id: detail.id,
    name: detail.name ?? '',
    description: detail.description ?? '',
    llm_id: config.llm_id ?? '',
    kind: detail.kind ?? '',
    config: base,
  };
};

export const transformGroupDetailToForm = (
  detail: ICompilationTemplateGroup,
): FormSchemaType => {
  const templates = (detail.templates ?? []).map((template) =>
    transformDetailToForm(template),
  );

  return {
    name: detail.name ?? '',
    description: detail.description ?? '',
    avatar: detail.avatar ?? '',
    templates: templates.length > 0 ? templates : [DefaultTemplateValues],
  };
};

export const transformTemplateToPayload = (template: TemplateSchemaType) => {
  const config: ICompilationTemplateConfigRequest = {
    kind: template.kind,
    llm_id: template.llm_id,
  };

  Object.entries(template.config).forEach(([key, value]) => {
    if (key === 'kind' || key === 'llm_id') return;
    if (key === 'instruction' || key === 'page_example') return;
    if (key === 'synthesis') {
      config[key] = value as ICompilationTemplateConfigRequest[string];
      return;
    }
    if (isConfigMetaKey(key)) {
      if (typeof value === 'string' || typeof value === 'boolean')
        config[key] = value;
    } else {
      config[key] = value as ICompilationTemplateConfigRequest[string];
    }
  });

  if (template.kind === CompilationTemplateKind.Artifacts) {
    if (template.config.use_blueprint) {
      const instruction = String(template.config.instruction ?? '').trim();
      const pageExample = String(template.config.page_example ?? '').trim();
      config.example = [instruction, pageExample].filter(Boolean).join('\n\n');
    } else {
      config.example = '';
    }
  }

  return {
    id: template.id,
    name: template.name,
    description: template.description,
    kind: template.kind,
    config,
  };
};

export const transformFormToPayload = (values: FormSchemaType) => {
  return {
    name: values.name,
    description: values.description,
    avatar: values.avatar || undefined,
    templates: values.templates.map((template) =>
      transformTemplateToPayload(template),
    ),
  };
};

export const sortSectionNames = (names: string[]): string[] => {
  const priority = SectionPriority.filter((name) => names.includes(name));
  const rest = names.filter((name) => !SectionPriority.includes(name));
  return [...priority, ...rest];
};

export const getTypeOptionsFromBuiltinSection = (
  builtinSection?: ICompilationTemplateSection,
) => {
  const typeSet = new Set<string>();
  builtinSection?.fields?.forEach((field) => {
    if (field.type) typeSet.add(field.type);
  });
  return Array.from(typeSet)
    .sort()
    .map((value) => ({ label: value, value }));
};
