/**
 * Report Builder — Composes the final ScanResult from processed findings.
 *
 * Encapsulates sorting, counting, suppressed-summary building, and result
 * object construction.
 */

import type {
  ScanResult,
  Vulnerability,
  SuppressedVulnerabilitySummary,
} from '../shared/types'
import type { ValidationStats } from '../validate'
import type { SuppressionResult } from '../postprocess/suppression/types'
import type { FilterPipeline } from '../postprocess/filtering/pipeline'
import { sortBySeverity, computeSeverityCounts, computeCategoryCounts } from './summary'

export interface BuildScanResultInput {
  repoInfo: { name: string; url: string; branch: string }
  files: { length: number }
  findings: Vulnerability[]
  suppressionResult: SuppressionResult
  startTime: number
  validationStats?: ValidationStats
  showSuppressed?: boolean
  filterPipeline?: FilterPipeline
  cancelled?: boolean
  cancelReason?: string
}

/**
 * Build the final ScanResult from postprocessed findings.
 */
export function buildScanResult(input: BuildScanResultInput): ScanResult {
  const {
    repoInfo,
    files,
    findings,
    suppressionResult,
    startTime,
    validationStats,
    showSuppressed,
    filterPipeline,
    cancelled,
    cancelReason,
  } = input

  // Use the filtered findings (after suppression)
  const afterSuppression = suppressionResult.findings

  // Sort by severity
  const sortedVulnerabilities = sortBySeverity(afterSuppression)

  // Compute issue-mix counts (based on unsuppressed findings)
  const severityCounts = computeSeverityCounts(sortedVulnerabilities)
  const categoryCounts = computeCategoryCounts(sortedVulnerabilities)
  const hasBlockingIssues = severityCounts.critical > 0 || severityCounts.high > 0

  // Build suppressed vulnerabilities summary (for --show-suppressed)
  const suppressedVulnerabilities: SuppressedVulnerabilitySummary[] | undefined = showSuppressed
    ? suppressionResult.suppressed.map(s => ({
        hash: s.suppression.hash,
        filePath: s.vulnerability.filePath,
        lineNumber: s.vulnerability.lineNumber,
        category: s.vulnerability.category,
        severity: s.vulnerability.severity,
        title: s.vulnerability.title,
        suppressionType: s.suppression.type,
        suppressionReason: s.suppression.reason,
        expires: s.suppression.expires,
      }))
    : undefined

  return {
    repoName: repoInfo.name,
    repoUrl: repoInfo.url,
    branch: repoInfo.branch,
    filesScanned: files.length,
    filesSkipped: 0, // TODO: track skipped files
    vulnerabilities: sortedVulnerabilities,
    severityCounts,
    categoryCounts,
    hasBlockingIssues: cancelled ? false : hasBlockingIssues,
    scanDuration: Date.now() - startTime,
    timestamp: new Date().toISOString(),
    validationStats,
    suppressionStats: suppressionResult.suppressed.length > 0 || suppressionResult.expiredSuppressions > 0
      ? suppressionResult.stats
      : undefined,
    suppressedVulnerabilities,
    filterAuditTrail: filterPipeline?.isEnabled ? filterPipeline.getAuditTrail() : undefined,
    ...(cancelled ? { cancelled: true, cancelReason } : {}),
  }
}
