/**
 * @fileoverview ComplianceReport mapper
 *
 * Maps between DeepSource API models and domain ComplianceReport aggregates.
 */

import { ComplianceReport } from '../../domain/aggregates/compliance-report/compliance-report.aggregate.js';
import { ComplianceReport as ApiComplianceReport } from '../../deepsource.js';
import {
  CreateComplianceReportParams,
  ComplianceCategory,
  ComplianceReportStatus,
} from '../../domain/aggregates/compliance-report/compliance-report.types.js';
import { asProjectKey, asGraphQLNodeId } from '../../types/branded.js';
import { IssueCount } from '../../domain/value-objects/issue-count.js';
import { ReportType } from '../../types/report-types.js';

/**
 * Maps the highest severity from occurrence distribution
 *
 * @param occurrence - The severity distribution
 * @returns The highest severity present
 */
function mapHighestSeverity(
  occurrence: ApiComplianceReport['securityIssueStats'][0]['occurrence']
): 'CRITICAL' | 'MAJOR' | 'MINOR' | 'INFO' {
  if (occurrence.critical > 0) return 'CRITICAL';
  if (occurrence.major > 0) return 'MAJOR';
  if (occurrence.minor > 0) return 'MINOR';
  return 'INFO';
}

/**
 * Maps the API report status to domain status
 *
 * @param apiStatus - The API status
 * @returns The domain report status
 */
function mapReportStatus(apiStatus?: string): ComplianceReportStatus {
  const statusMap: Record<string, ComplianceReportStatus> = {
    READY: 'READY',
    COMPLETED: 'READY',
    GENERATING: 'GENERATING',
    PENDING: 'GENERATING',
    ERROR: 'ERROR',
    FAILED: 'ERROR',
    PASSING: 'PASSING',
    FAILING: 'FAILING',
    NOOP: 'NOT_APPLICABLE',
  };

  return statusMap[apiStatus || ''] || 'PENDING';
}
/**
 * Maps a DeepSource API compliance report to domain ComplianceReport aggregate
 *
 * @param apiReport - The API compliance report model
 * @param projectKey - The project key
 * @param repositoryId - The repository GraphQL ID
 * @returns The domain ComplianceReport aggregate
 */
export function mapComplianceReportToDomain(
  apiReport: ApiComplianceReport,
  projectKey: string,
  repositoryId: string
): ComplianceReport {
  const categories: ComplianceCategory[] = apiReport.securityIssueStats.map((stat) => {
    // API provides total directly, but we can also calculate it for verification
    const totalIssues =
      stat.occurrence.total ||
      stat.occurrence.critical + stat.occurrence.major + stat.occurrence.minor;

    // Simple approach: treat all detected issues as non-compliant
    // In a real implementation, this would depend on business rules about what constitutes compliance
    return {
      name: stat.title,
      description: `Security category: ${stat.key}`,
      compliant: IssueCount.create(0), // API doesn't provide compliant count directly
      nonCompliant: IssueCount.create(totalIssues),
      issueCount: IssueCount.create(totalIssues),
      severity: mapHighestSeverity(stat.occurrence),
    };
  });

  const params: CreateComplianceReportParams = {
    projectKey: asProjectKey(projectKey),
    repositoryId: asGraphQLNodeId(repositoryId),
    reportType: apiReport.key,
    status: mapReportStatus(apiReport.status),
    categories,
  };

  return ComplianceReport.create(params);
}

/**
 * Maps a domain ComplianceReport aggregate to persistence format
 *
 * @param report - The domain ComplianceReport aggregate
 * @returns The persistence model
 */
export function mapComplianceReportToPersistence(report: ComplianceReport): {
  id: string;
  projectKey: string;
  repositoryId: string;
  reportType: ReportType;
  status: ComplianceReportStatus;
  categories: ComplianceCategory[];
  generatedAt: Date;
  lastUpdated: Date;
} {
  const persistence = report.toPersistence();
  return {
    ...persistence,
    projectKey: persistence.projectKey as string,
    repositoryId: persistence.repositoryId as string,
  };
}

/**
 * Creates a category from API security issue stat
 *
 * @param stat - The API security issue statistic
 * @param reportType - The report type for context
 * @returns A compliance category
 */
export function createCategoryFromStat(
  stat: {
    key: string;
    title: string;
    occurrence: { critical: number; major: number; minor: number; total: number };
  },
  reportType: ReportType
): ComplianceCategory {
  // API provides total directly, but we can also calculate it for verification
  const totalIssues =
    stat.occurrence.total ||
    stat.occurrence.critical + stat.occurrence.major + stat.occurrence.minor;

  return {
    name: stat.title,
    description: `${reportType} category: ${stat.key}`,
    compliant: IssueCount.create(0), // We don't have compliant count from API
    nonCompliant: IssueCount.create(totalIssues),
    issueCount: IssueCount.create(totalIssues),
    severity: mapHighestSeverity(stat.occurrence),
  };
}

/**
 * Estimates compliance score based on issue counts
 * This is a simplified calculation since the API doesn't provide the exact score
 *
 * @param categories - The compliance categories
 * @returns Estimated compliance score (0-100)
 */
export function estimateComplianceScore(categories: ComplianceCategory[]): number {
  if (categories.length === 0) return 100;

  const totalIssues = categories.reduce((sum, cat) => sum + cat.issueCount.count, 0);
  const criticalIssues = categories.filter((cat) => cat.severity === 'CRITICAL').length;
  const majorIssues = categories.filter((cat) => cat.severity === 'MAJOR').length;

  // Simple scoring: penalize critical and major issues more heavily
  const penalty = criticalIssues * 20 + majorIssues * 10 + totalIssues * 2;
  return Math.max(0, Math.min(100, 100 - penalty));
}

/**
 * Maps multiple API compliance reports to domain aggregates
 *
 * @param apiReports - Array of API compliance reports
 * @param projectKey - The project key
 * @param repositoryId - The repository GraphQL ID
 * @returns Array of domain ComplianceReport aggregates
 */
export function mapComplianceReportsFromList(
  apiReports: ApiComplianceReport[],
  projectKey: string,
  repositoryId: string
): ComplianceReport[] {
  return apiReports.map((report) => mapComplianceReportToDomain(report, projectKey, repositoryId));
}

// For backward compatibility, export a namespace with the old static methods
export const ComplianceReportMapper = {
  toDomain: mapComplianceReportToDomain,
  mapStatus: mapReportStatus,
  mapHighestSeverity,
  toPersistence: mapComplianceReportToPersistence,
  toDomainFromList: mapComplianceReportsFromList,
  createCategoryFromStat,
  estimateComplianceScore,
};
