import {
  classifyTemplateField,
  computeFieldDiff,
  createSqlClient,
  getEffectiveMappedKeys,
  extractTemplateFields,
  getActiveTemplateVersions,
  getDuplicateFieldNames,
  getMappingsForVersion,
  getUnknownFieldNames,
  summarizeIssues
} from './pdf-audit-utils.ts';

async function main() {
  const sql = createSqlClient();

  try {
    const templates = await getActiveTemplateVersions(sql);
    const results = [];

    for (const template of templates) {
      const fields = extractTemplateFields(template.schemaJson);
      const previousVersion =
        (
          await sql`
            select schema_json as "schemaJson", version
            from crm_document_template_versions
            where template_id = ${template.templateId}
              and deleted_at is null
              and id <> ${template.versionId}
            order by created_at desc
            limit 1
          `
        )[0] ?? null;
      const previousFields = previousVersion
        ? extractTemplateFields(previousVersion.schemaJson)
        : [];
      const { mappings } = await getMappingsForVersion(sql, template.versionId);
      const fieldNames = new Set(fields.map((field) => field.name).filter(Boolean));
      const mappedKeys = getEffectiveMappedKeys(fields, mappings);
      const duplicateFields = getDuplicateFieldNames(fields);
      const unknownFields = getUnknownFieldNames(fields, mappedKeys);
      const fieldDiff = computeFieldDiff(fields, previousFields);
      const requiredTableFields = ['quotation_price_data'];
      const missingRequiredTableFields = requiredTableFields.filter(
        (fieldName) => !fields.some((field) => field.name === fieldName && field.type === 'table')
      );
      const tableFields = fields.filter((field) => field.type === 'table').map((field) => field.name);
      const dynamicTopicFields = fields
        .filter((field) => field.name === 'topic' || field.name === 'data_topic')
        .map((field) => field.name);
      const placeholderTokens = new Set(fields.flatMap((field) => field.tokens));
      const missingMappings = [...placeholderTokens].filter(
        (token) => token !== 'item_topic' && !mappedKeys.has(token)
      );
      const orphanMappings = mappings
        .filter(
          (mapping) =>
            !placeholderTokens.has(mapping.placeholderKey) &&
            !fieldNames.has(mapping.placeholderKey) &&
            mapping.placeholderKey !== 'items_table'
        )
        .map((mapping) => mapping.placeholderKey);
      const classifications = fields.map((field) => ({
        name: field.name,
        type: field.type,
        classification: classifyTemplateField(field, mappedKeys)
      }));
      const status = summarizeIssues([
        duplicateFields.length ? 'FAIL' : 'PASS',
        missingRequiredTableFields.length ? 'FAIL' : 'PASS',
        missingMappings.length ? 'FAIL' : 'PASS',
        orphanMappings.length ? 'WARNING' : 'PASS',
        unknownFields.length ? 'WARNING' : 'PASS'
      ]);

      results.push({
        templateName: template.templateName,
        version: template.version,
        previousVersion: previousVersion?.version ?? null,
        organizationId: template.organizationId,
        schemaFieldCount: fields.length,
        tableFields,
        missingRequiredTableFields,
        dynamicTopicFields,
        deletedFields: fieldDiff.deletedFields,
        newFields: fieldDiff.newFields,
        duplicateFields,
        unknownFields,
        classifications,
        missingMappings,
        orphanMappings,
        mappedFieldCount: mappings.length,
        status
      });
    }

    const overallStatus = summarizeIssues(
      results.map((result) => result.status) as Array<'PASS' | 'WARNING' | 'FAIL'>
    );

    console.log(
      JSON.stringify(
        {
          audit: 'template-inventory',
          overallStatus,
          templateCount: results.length,
          results
        },
        null,
        2
      )
    );
  } finally {
    await sql.end({ timeout: 5 });
  }
}

main().catch((error) => {
  console.error(`[audit-pdf-template-inventory] ${error.message}`);
  process.exit(1);
});
