import type { Template } from '@pdfme/common';
import type {
  CompatibleTemplate,
  CompatibleTemplatePage,
  ResolvedTemplate,
  RuntimeIssue,
  SectionRole,
} from './runtime-contracts';

const EXPLICIT_ROLE_PREFIXES = ['__section_role__', '__page_role__'] as const;

const LEGACY_MARKERS: Record<Exclude<SectionRole, 'unknown'>, string[]> = {
  customer: ['customer_name', 'quotation_price_data', 'quotation_code_data'],
  product_items: ['items_table'],
  topics: ['topic', 'data_topic'],
  conditions: ['conditions', 'condition_data'],
  signature: [
    'Please_do_not',
    'yours_faithfuly',
    'app1',
    'app1_position',
    'app2',
    'app2_position',
    'app3',
    'app3_position',
  ],
  attachments: ['attachment'],
  appendix: ['appendix'],
  warranty: ['warranty'],
  cover: ['cover'],
};

type TemplateField = {
  name?: string;
  content?: string;
};

function createIssue(issue: RuntimeIssue): RuntimeIssue {
  return issue;
}

function isTemplatePageArray(
  value: Template['schemas'][number] | unknown,
): value is Template['schemas'][number] {
  return Array.isArray(value);
}

function getFieldNames(page: Template['schemas'][number]): string[] {
  return page
    .map((field) => {
      if (!field || typeof field !== 'object' || !('name' in field)) {
        return '';
      }

      return String((field as TemplateField).name ?? '');
    })
    .filter(Boolean);
}

function isSectionRole(value: string | null | undefined): value is SectionRole {
  return value !== undefined && value !== null && (
    value === 'customer' ||
    value === 'product_items' ||
    value === 'topics' ||
    value === 'conditions' ||
    value === 'signature' ||
    value === 'attachments' ||
    value === 'appendix' ||
    value === 'warranty' ||
    value === 'cover' ||
    value === 'unknown'
  );
}

function getExplicitRoles(page: Template['schemas'][number]): SectionRole[] {
  const roles = new Set<SectionRole>();

  for (const field of page) {
    if (!field || typeof field !== 'object') {
      continue;
    }

    const name = 'name' in field && typeof field.name === 'string' ? field.name : null;
    const content =
      'content' in field && typeof field.content === 'string'
        ? field.content.trim()
        : null;

    for (const prefix of EXPLICIT_ROLE_PREFIXES) {
      const byName = name?.startsWith(prefix) ? name.slice(prefix.length) : null;

      if (isSectionRole(byName)) {
        roles.add(byName);
      }
    }

    if (isSectionRole(content)) {
      roles.add(content);
    }
  }

  return [...roles];
}

function inferLegacyRoles(page: Template['schemas'][number]): SectionRole[] {
  const fieldNames = new Set(getFieldNames(page));
  const roles: SectionRole[] = [];

  for (const [role, markers] of Object.entries(LEGACY_MARKERS) as Array<
    [Exclude<SectionRole, 'unknown'>, string[]]
  >) {
    if (markers.every((marker) => fieldNames.has(marker))) {
      roles.push(role);
    }
  }

  return roles;
}

export function adaptTemplateForSectionRuntime(
  template: ResolvedTemplate,
): CompatibleTemplate {
  const schemaPages = template.schema.schemas;
  const issues: RuntimeIssue[] = [];

  if (!Array.isArray(schemaPages)) {
    return {
      template,
      pages: [],
      issues: [
        createIssue({
          code: 'INVALID_TEMPLATE',
          severity: 'error',
          message: 'PDF template schema does not expose a valid schemas array.',
        }),
      ],
    };
  }

  const pages: CompatibleTemplatePage[] = [];

  for (const [pageIndex, rawPage] of schemaPages.entries()) {
    if (!isTemplatePageArray(rawPage)) {
      issues.push(
        createIssue({
          code: 'INVALID_TEMPLATE',
          severity: 'error',
          message: 'PDF template page schema is invalid.',
          details: { pageIndex },
        }),
      );
      continue;
    }

    const explicitRoles = getExplicitRoles(rawPage);
    const inferredRoles = inferLegacyRoles(rawPage);
    const primaryRole = explicitRoles[0] ?? inferredRoles[0] ?? 'unknown';
    const roles = Array.from(
      new Set(
        [primaryRole, ...explicitRoles, ...inferredRoles].filter(isSectionRole),
      ),
    );

    let strategy: CompatibleTemplatePage['strategy'] = 'fallback';

    if (explicitRoles.length > 0) {
      strategy = 'explicit_marker';
    } else if (inferredRoles.length > 0) {
      strategy = 'legacy_inference';
      issues.push(
        createIssue({
          code: 'LEGACY_COMPAT_MODE',
          severity: 'warning',
          message: 'PDF template page role inferred from legacy field markers.',
          details: { pageIndex, roles },
        }),
      );
    } else {
      issues.push(
        createIssue({
          code: 'MISSING_MARKER',
          severity: 'warning',
          message:
            'PDF template page could not be classified by explicit marker or legacy inference.',
          details: { pageIndex },
        }),
      );
    }

    pages.push({
      pageIndex,
      primaryRole,
      roles: roles.length > 0 ? roles : ['unknown'],
      strategy,
      schema: rawPage,
    });
  }

  return {
    template,
    pages,
    issues,
  };
}
