const fs = require('node:fs');
const path = require('node:path');
const postgres = require('postgres');

function loadEnvFile(filePath) {
  if (!fs.existsSync(filePath)) {
    return;
  }

  const content = fs.readFileSync(filePath, 'utf8');

  for (const rawLine of content.split(/\r?\n/)) {
    const line = rawLine.trim();

    if (!line || line.startsWith('#')) {
      continue;
    }

    const separatorIndex = line.indexOf('=');

    if (separatorIndex === -1) {
      continue;
    }

    const key = line.slice(0, separatorIndex).trim();
    let value = line.slice(separatorIndex + 1).trim();

    if (
      (value.startsWith('"') && value.endsWith('"')) ||
      (value.startsWith("'") && value.endsWith("'"))
    ) {
      value = value.slice(1, -1);
    }

    if (!(key in process.env)) {
      process.env[key] = value;
    }
  }
}

function loadLocalEnv() {
  loadEnvFile(path.resolve(process.cwd(), '.env.local'));
  loadEnvFile(path.resolve(process.cwd(), '.env'));
}

function assert(condition, message) {
  if (!condition) {
    throw new Error(message);
  }
}

function pickSnapshotValue(snapshot, pathSegments) {
  return pathSegments.reduce((value, segment) => {
    if (!value || typeof value !== 'object') {
      return undefined;
    }

    return value[segment];
  }, snapshot);
}

async function main() {
  loadLocalEnv();

  const databaseUrl = process.env.DATABASE_URL?.trim();

  assert(databaseUrl, 'Missing DATABASE_URL');

  const sql = postgres(databaseUrl, { max: 1 });

  try {
    const mappingRows = await sql`
      select placeholder_key, source_path
      from crm_document_template_mappings
      where placeholder_key in ('app1', 'app1_position', 'app2', 'app2_position', 'app3', 'app3_position')
        and deleted_at is null
      order by placeholder_key asc
    `;
    const mappingMap = new Map(mappingRows.map((row) => [row.placeholder_key, row.source_path]));

    assert(mappingMap.get('app1') === 'signatures.preparedBy.name', 'app1 mapping is incorrect');
    assert(
      mappingMap.get('app1_position') === 'signatures.preparedBy.position',
      'app1_position mapping is incorrect'
    );
    assert(mappingMap.get('app2') === 'signatures.approvedBy.name', 'app2 mapping is incorrect');
    assert(
      mappingMap.get('app2_position') === 'signatures.approvedBy.position',
      'app2_position mapping is incorrect'
    );
    assert(mappingMap.get('app3') === 'signatures.authorizedBy.name', 'app3 mapping is incorrect');
    assert(
      mappingMap.get('app3_position') === 'signatures.authorizedBy.position',
      'app3_position mapping is incorrect'
    );

    const [snapshotRow] = await sql`
      select
        q.id,
        q.code,
        q.organization_id,
        q.approved_snapshot
      from crm_quotations q
      where q.approved_snapshot is not null
        and q.deleted_at is null
      order by q.updated_at desc
      limit 1
    `;

    assert(
      snapshotRow,
      'No quotation with approved_snapshot was found. Generate at least one approved PDF before running verify-task-h3.'
    );

    const snapshot = snapshotRow.approved_snapshot;
    const signatures = pickSnapshotValue(snapshot, ['documentData', 'signatures']);
    const templateInput = pickSnapshotValue(snapshot, ['templateInput']);

    assert(signatures && typeof signatures === 'object', 'approvedSnapshot is missing signatures');

    if (
      typeof signatures.preparedBy === 'string' ||
      typeof signatures.salesManager === 'string' ||
      typeof signatures.topManager === 'string'
    ) {
      throw new Error(
        'approvedSnapshot still uses the pre-H3 signature shape. Regenerate one approved PDF to backfill snapshot signatures.'
      );
    }

    for (const key of ['preparedBy', 'approvedBy', 'authorizedBy']) {
      const block = signatures[key];

      assert(block && typeof block === 'object', `approvedSnapshot is missing ${key}`);
      assert(
        typeof block.name === 'string' && block.name.trim().length > 0 && block.name !== '-',
        `approvedSnapshot ${key}.name is missing`
      );
      assert(
        typeof block.position === 'string' && block.position.trim().length > 0 && block.position !== '-',
        `approvedSnapshot ${key}.position is missing`
      );
    }

    assert(templateInput && typeof templateInput === 'object', 'approvedSnapshot is missing templateInput');
    assert(templateInput.app1 === signatures.preparedBy.name, 'templateInput.app1 does not match preparedBy');
    assert(
      templateInput.app1_position === signatures.preparedBy.position,
      'templateInput.app1_position does not match preparedBy.position'
    );
    assert(templateInput.app2 === signatures.approvedBy.name, 'templateInput.app2 does not match approvedBy');
    assert(
      templateInput.app2_position === signatures.approvedBy.position,
      'templateInput.app2_position does not match approvedBy.position'
    );
    assert(
      templateInput.app3 === signatures.authorizedBy.name,
      'templateInput.app3 does not match authorizedBy'
    );
    assert(
      templateInput.app3_position === signatures.authorizedBy.position,
      'templateInput.app3_position does not match authorizedBy.position'
    );

    const jobTitleRows = await sql`
      select code, label
      from ms_options
      where organization_id = ${snapshotRow.organization_id}
        and category = 'crm_job_title'
        and deleted_at is null
        and is_active = true
      order by sort_order asc
    `;

    assert(jobTitleRows.length >= 5, 'crm_job_title master options are incomplete');

    console.log(
      JSON.stringify(
        {
          success: true,
          quotationId: snapshotRow.id,
          quotationCode: snapshotRow.code,
          verifiedMappings: [...mappingMap.entries()],
          verifiedJobTitles: jobTitleRows
        },
        null,
        2
      )
    );
  } finally {
    await sql.end({ timeout: 5 });
  }
}

main().catch((error) => {
  console.error(`[verify-task-h3] ${error.message}`);
  process.exit(1);
});
