'use strict';

/** @typedef {import('./validator-types').Issue} Issue */
/** @typedef {import('./validator-types').JsonReport} JsonReport */

const SCHEMA_VERSION = '1.0';

/**
 * Print issues + summary in human-readable format. Errors go to stderr,
 * warnings to stderr as well (so they are visible alongside errors when piping
 * stdout to a file). The summary line goes to stdout when no errors, stderr
 * otherwise, mirroring exit-code semantics.
 *
 * @param {Issue[]} issues
 * @param {number} modelsLoaded
 */
function reportHuman(issues, modelsLoaded) {
  const errorCount = countSeverity(issues, 'error');
  const warningCount = countSeverity(issues, 'warning');

  for (const issue of issues) {
    const prefix = issue.severity === 'error' ? '✗' : '⚠';
    const stream = issue.severity === 'error' ? console.error : console.warn;
    stream(`${prefix} ${issue.message}`);
  }

  if (issues.length > 0) {
    console.error('');
  } else {
    console.log('');
  }

  const summary = buildSummaryLine(modelsLoaded, errorCount, warningCount);
  if (errorCount > 0) {
    console.error(summary);
  } else {
    console.log(summary);
  }
}

/**
 * Produce machine-readable JSON report. Caller is responsible for printing.
 *
 * @param {Issue[]} issues
 * @param {number} modelsLoaded
 * @returns {JsonReport}
 */
function reportJson(issues, modelsLoaded) {
  return {
    schemaVersion: SCHEMA_VERSION,
    summary: {
      modelsLoaded,
      errorCount: countSeverity(issues, 'error'),
      warningCount: countSeverity(issues, 'warning')
    },
    issues: issues.map(normalizeIssueForJson)
  };
}

/**
 * Compute process exit code from issue list.
 *
 * - Any error → 1
 * - Warning only → 0, unless `strictWarnings` is true
 * - Otherwise → 0
 *
 * @param {Issue[]} issues
 * @param {boolean} strictWarnings
 * @returns {number}
 */
function getExitCode(issues, strictWarnings) {
  if (issues.some((i) => i.severity === 'error')) return 1;
  if (strictWarnings && issues.some((i) => i.severity === 'warning')) return 1;
  return 0;
}

function countSeverity(issues, severity) {
  let count = 0;
  for (const issue of issues) {
    if (issue.severity === severity) count++;
  }
  return count;
}

function buildSummaryLine(modelsLoaded, errorCount, warningCount) {
  const modelsLabel = `${modelsLoaded} ${pluralize('model', modelsLoaded)} loaded`;
  const errorLabel = `${errorCount} ${pluralize('error', errorCount)}`;
  const parts = [modelsLabel, errorLabel];
  if (warningCount > 0) {
    parts.push(`${warningCount} ${pluralize('warning', warningCount)}`);
  }
  return parts.join(', ') + '.';
}

function pluralize(noun, count) {
  return count === 1 ? noun : `${noun}s`;
}

function normalizeIssueForJson(issue) {
  // Stable property order for deterministic JSON output.
  const out = {
    severity: issue.severity,
    code: issue.code,
    message: issue.message
  };
  if (issue.file !== undefined) out.file = issue.file;
  if (issue.table !== undefined) out.table = issue.table;
  if (issue.field !== undefined) out.field = issue.field;
  if (issue.relation !== undefined) out.relation = issue.relation;
  return out;
}

module.exports = {
  SCHEMA_VERSION,
  reportHuman,
  reportJson,
  getExitCode
};
