## Quantum-Resistant Cryptographic Transitions
##
## This module implements the algorithm migration framework for transitioning
## from current cryptographic algorithms to quantum-resistant alternatives.
## It provides backward compatibility, algorithm detection, validation, and
## upgrade procedures for all package formats.

import std/[times, tables, options, json, strutils, algorithm]
import ./types_fixed

# =============================================================================
# Algorithm Migration Framework
# =============================================================================

type
  AlgorithmMigration* = object
    ## Specification for migrating from one algorithm to another
    fromAlgorithm*: string
    toAlgorithm*: string
    migrationDate*: times.DateTime
    mandatory*: bool
    compatibility*: bool  ## Whether old and new can coexist
    description*: string
    phaseOutDate*: times.DateTime

  MigrationPlan* = object
    ## Complete migration plan for cryptographic algorithms
    hashMigrations*: seq[AlgorithmMigration]
    signatureMigrations*: seq[AlgorithmMigration]
    targetDate*: times.DateTime
    phaseOutDate*: times.DateTime
    backwardCompatible*: bool

  MigrationStatus* = enum
    ## Current status of algorithm migration
    NotStarted,     ## Migration not yet begun
    InProgress,     ## Migration in progress, dual support
    Completed,      ## Migration complete, new algorithm preferred
    PhaseOut,       ## Old algorithm being phased out
    Deprecated      ## Old algorithm deprecated, should not be used

  CryptoTransition* = object
    ## State of cryptographic algorithm transition
    currentAlgorithms*: CryptoAlgorithms
    targetAlgorithms*: CryptoAlgorithms
    transitionPhase*: TransitionPhase
    migrationPlan*: MigrationPlan
    compatibilityMode*: bool

  TransitionPhase* = enum
    ## Phases of cryptographic algorithm transition
    PreTransition,    ## Before transition starts
    DualSupport,      ## Supporting both old and new algorithms
    NewPreferred,     ## New algorithms preferred, old still supported
    NewOnly,          ## Only new algorithms supported
    PostTransition    ## Transition complete

  AlgorithmCompatibility* = object
    ## Compatibility information between algorithms
    algorithm*: string
    quantumResistant*: bool
    supportedUntil*: times.DateTime
    replacementAlgorithm*: string
    migrationComplexity*: MigrationComplexity

  MigrationComplexity* = enum
    ## Complexity level of algorithm migration
    Simple,     ## Drop-in replacement
    Moderate,   ## Requires format changes
    Complex,    ## Requires significant restructuring
    Breaking    ## Incompatible, requires full rebuild

# =============================================================================
# Quantum-Resistant Algorithm Definitions
# =============================================================================

const
  ## Quantum-resistant algorithm specifications
  QUANTUM_RESISTANT_ALGORITHMS* = {
    # Hash algorithms
    "SHA3-512": AlgorithmCompatibility(
      algorithm: "SHA3-512",
      quantumResistant: true,
      supportedUntil: dateTime(2050, mDec, 31),
      replacementAlgorithm: "",
      migrationComplexity: Simple
    ),
    "BLAKE3": AlgorithmCompatibility(
      algorithm: "BLAKE3",
      quantumResistant: true,
      supportedUntil: dateTime(2040, mDec, 31),
      replacementAlgorithm: "SHA3-512",
      migrationComplexity: Simple
    ),

    # Signature algorithms
    "Dilithium": AlgorithmCompatibility(
      algorithm: "Dilithium",
      quantumResistant: true,
      supportedUntil: dateTime(2050, mDec, 31),
      replacementAlgorithm: "",
      migrationComplexity: Moderate
    ),
    "SPHINCS+": AlgorithmCompatibility(
      algorithm: "SPHINCS+",
      quantumResistant: true,
      supportedUntil: dateTime(2050, mDec, 31),
      replacementAlgorithm: "",
      migrationComplexity: Complex
    )
  }.toTable()

  ## Legacy algorithm migration paths
  LEGACY_ALGORITHM_MIGRATIONS* = {
    # Hash algorithm transitions
    "BLAKE2b": AlgorithmCompatibility(
      algorithm: "BLAKE2b",
      quantumResistant: false,
      supportedUntil: dateTime(2030, mDec, 31),
      replacementAlgorithm: "BLAKE3",
      migrationComplexity: Simple
    ),
    "SHA256": AlgorithmCompatibility(
      algorithm: "SHA256",
      quantumResistant: false,
      supportedUntil: dateTime(2028, mDec, 31),
      replacementAlgorithm: "SHA3-512",
      migrationComplexity: Simple
    ),

    # Signature algorithm transitions
    "Ed25519": AlgorithmCompatibility(
      algorithm: "Ed25519",
      quantumResistant: false,
      supportedUntil: dateTime(2030, mDec, 31),
      replacementAlgorithm: "Dilithium",
      migrationComplexity: Moderate
    ),
    "RSA-4096": AlgorithmCompatibility(
      algorithm: "RSA-4096",
      quantumResistant: false,
      supportedUntil: dateTime(2028, mDec, 31),
      replacementAlgorithm: "Dilithium",
      migrationComplexity: Complex
    )
  }.toTable()

  ## Complete migration timeline
  QUANTUM_MIGRATION_TIMELINE* = MigrationPlan(
    hashMigrations: @[
      AlgorithmMigration(
        fromAlgorithm: "BLAKE2b",
        toAlgorithm: "BLAKE3",
        migrationDate: dateTime(2025, mJan, 1),
        mandatory: false,
        compatibility: true,
        description: "Performance and quantum-resistance improvement",
        phaseOutDate: dateTime(2030, mDec, 31)
      ),
      AlgorithmMigration(
        fromAlgorithm: "BLAKE3",
        toAlgorithm: "SHA3-512",
        migrationDate: dateTime(2030, mJan, 1),
        mandatory: true,
        compatibility: true,
        description: "Full quantum resistance transition",
        phaseOutDate: dateTime(2035, mDec, 31)
      ),
      AlgorithmMigration(
        fromAlgorithm: "SHA256",
        toAlgorithm: "SHA3-512",
        migrationDate: dateTime(2028, mJan, 1),
        mandatory: true,
        compatibility: false,
        description: "Direct quantum resistance upgrade",
        phaseOutDate: dateTime(2030, mDec, 31)
      )
    ],
    signatureMigrations: @[
      AlgorithmMigration(
        fromAlgorithm: "Ed25519",
        toAlgorithm: "Dilithium",
        migrationDate: dateTime(2028, mJan, 1),
        mandatory: true,
        compatibility: false,
        description: "Quantum-resistant signature transition",
        phaseOutDate: dateTime(2032, mDec, 31)
      ),
      AlgorithmMigration(
        fromAlgorithm: "RSA-4096",
        toAlgorithm: "Dilithium",
        migrationDate: dateTime(2026, mJan, 1),
        mandatory: true,
        compatibility: false,
        description: "Legacy RSA to quantum-resistant transition",
        phaseOutDate: dateTime(2030, mDec, 31)
      )
    ],
    targetDate: dateTime(2030, mDec, 31),
    phaseOutDate: dateTime(2035, mDec, 31),
    backwardCompatible: true
  )

# =============================================================================
# Algorithm Detection and Validation
# =============================================================================

proc isQuantumResistant*(algorithm: string): bool =
  ## Check if an algorithm is quantum-resistant
  algorithm in QUANTUM_RESISTANT_ALGORITHMS

proc isQuantumResistant*(algorithms: CryptoAlgorithms): bool =
  ## Check if cryptographic algorithms are quantum-resistant
  isQuantumResistant(algorithms.hashAlgorithm) and
  isQuantumResistant(algorithms.signatureAlgorithm)

proc getAlgorithmCompatibility*(algorithm: string): Option[AlgorithmCompatibility] =
  ## Get compatibility information for an algorithm
  if algorithm in QUANTUM_RESISTANT_ALGORITHMS:
    return some(QUANTUM_RESISTANT_ALGORITHMS[algorithm])
  elif algorithm in LEGACY_ALGORITHM_MIGRATIONS:
    return some(LEGACY_ALGORITHM_MIGRATIONS[algorithm])
  else:
    return none(AlgorithmCompatibility)

proc getMigrationStatus*(algorithm: string, currentDate: times.DateTime = now()): MigrationStatus =
  ## Get current migration status for an algorithm
  let compatInfo = getAlgorithmCompatibility(algorithm)
  if compatInfo.isNone:
    return NotStarted

  let compat = compatInfo.get()

  if compat.quantumResistant:
    return Completed

  let timeToSupport = compat.supportedUntil - currentDate
  let gracePeriod = initDuration(days = 365)  # 1 year grace period

  if timeToSupport > initDuration(days = 730):  # 2+ years
    return NotStarted
  elif timeToSupport > initDuration(days = 365):  # 1-2 years
    return InProgress
  elif timeToSupport > initDuration(days = 0):  # 0-1 year
    return Completed
  elif timeToSupport > -gracePeriod:  # Grace period
    return PhaseOut
  else:
    return Deprecated

proc validateAlgorithmSupport*(algorithms: CryptoAlgorithms,
                              currentDate: times.DateTime = now()): seq[string] =
  ## Validate algorithm support and return warnings/errors
  var issues: seq[string] = @[]

  # Check hash algorithm
  let hashStatus = getMigrationStatus(algorithms.hashAlgorithm, currentDate)
  case hashStatus:
  of Deprecated:
    issues.add("CRITICAL: Hash algorithm " & algorithms.hashAlgorithm & " is deprecated")
  of PhaseOut:
    issues.add("WARNING: Hash algorithm " & algorithms.hashAlgorithm & " is being phased out")
  of InProgress:
    issues.add("INFO: Hash algorithm " & algorithms.hashAlgorithm & " migration in progress")
  else:
    discard

  # Check signature algorithm
  let sigStatus = getMigrationStatus(algorithms.signatureAlgorithm, currentDate)
  case sigStatus:
  of Deprecated:
    issues.add("CRITICAL: Signature algorithm " & algorithms.signatureAlgorithm & " is deprecated")
  of PhaseOut:
    issues.add("WARNING: Signature algorithm " & algorithms.signatureAlgorithm & " is being phased out")
  of InProgress:
    issues.add("INFO: Signature algorithm " & algorithms.signatureAlgorithm & " migration in progress")
  else:
    discard

  # Check version compatibility
  if algorithms.version == "1.0" and isQuantumResistant(algorithms):
    issues.add("INFO: Quantum-resistant algorithms should use version 2.0 or higher")

  return issues

# =============================================================================
# Algorithm Migration and Upgrade Procedures
# =============================================================================

proc getRecommendedAlgorithms*(currentAlgorithms: CryptoAlgorithms,
                              targetDate: times.DateTime = now()): CryptoAlgorithms =
  ## Get recommended algorithms for the target date
  var recommended = currentAlgorithms

  # Find appropriate hash algorithm migration
  for migration in QUANTUM_MIGRATION_TIMELINE.hashMigrations:
    if migration.fromAlgorithm == currentAlgorithms.hashAlgorithm and
       targetDate >= migration.migrationDate:
      recommended.hashAlgorithm = migration.toAlgorithm
      break

  # Find appropriate signature algorithm migration
  for migration in QUANTUM_MIGRATION_TIMELINE.signatureMigrations:
    if migration.fromAlgorithm == currentAlgorithms.signatureAlgorithm and
       targetDate >= migration.migrationDate:
      recommended.signatureAlgorithm = migration.toAlgorithm
      break

  # Update version if algorithms changed
  if recommended.hashAlgorithm != currentAlgorithms.hashAlgorithm or
     recommended.signatureAlgorithm != currentAlgorithms.signatureAlgorithm:
    if isQuantumResistant(recommended):
      recommended.version = "2.0"
    else:
      recommended.version = "1.5"  # Intermediate version

  return recommended

proc migrateToQuantumResistant*(algorithms: var CryptoAlgorithms): bool =
  ## Migrate algorithms to quantum-resistant alternatives
  let original = algorithms
  algorithms = getRecommendedAlgorithms(algorithms, dateTime(2030, mDec, 31))

  return algorithms.hashAlgorithm != original.hashAlgorithm or
         algorithms.signatureAlgorithm != original.signatureAlgorithm

proc createMigrationPlan*(currentAlgorithms: CryptoAlgorithms,
                         targetDate: times.DateTime): CryptoTransition =
  ## Create comprehensive migration plan for current algorithms
  let targetAlgorithms = getRecommendedAlgorithms(currentAlgorithms, targetDate)
  let phase = getCurrentTransitionPhase(currentAlgorithms, targetDate)

  CryptoTransition(
    currentAlgorithms: currentAlgorithms,
    targetAlgorithms: targetAlgorithms,
    transitionPhase: phase,
    migrationPlan: QUANTUM_MIGRATION_TIMELINE,
    compatibilityMode: currentAlgorithms.hashAlgorithm != targetAlgorithms.hashAlgorithm or
                      currentAlgorithms.signatureAlgorithm != targetAlgorithms.signatureAlgorithm
  )

proc getCurrentTransitionPhase*(algorithms: CryptoAlgorithms,
                               currentDate: times.DateTime = now()): TransitionPhase =
  ## Determine current transition phase based on algorithms and date
  if isQuantumResistant(algorithms):
    return PostTransition

  let hashStatus = getMigrationStatus(algorithms.hashAlgorithm, currentDate)
  let sigStatus = getMigrationStatus(algorithms.signatureAlgorithm, currentDate)

  # Determine overall phase based on most restrictive status
  let overallStatus = if hashStatus > sigStatus: hashStatus else: sigStatus

  case overallStatus:
  of NotStarted:
    return PreTransition
  of InProgress:
    return DualSupport
  of Completed:
    return NewPreferred
  of PhaseOut:
    return NewOnly
  of Deprecated:
    return PostTransition

# =============================================================================
# Backward Compatibility Management
# =============================================================================

type
  CompatibilityLayer* = object
    ## Compatibility layer for mixed-algorithm environments
    primaryAlgorithms*: CryptoAlgorithms
    fallbackAlgorithms*: seq[CryptoAlgorithms]
    verificationStrategy*: VerificationStrategy
    migrationDeadline*: times.DateTime

  VerificationStrategy* = enum
    ## Strategy for verifying signatures in mixed environments
    PrimaryOnly,           ## Only use primary algorithms
    TryPrimaryThenFallback, ## Try primary, fall back to legacy
    RequireBoth,           ## Require both primary and fallback verification
    LegacyOnly             ## Only use legacy algorithms (deprecated)

proc createCompatibilityLayer*(primaryAlgorithms: CryptoAlgorithms,
                              fallbackAlgorithms: seq[CryptoAlgorithms]): CompatibilityLayer =
  ## Create compatibility layer for mixed-algorithm environments
  let migrationDeadline =
    if primaryAlgorithms.hashAlgorithm in LEGACY_ALGORITHM_MIGRATIONS:
      LEGACY_ALGORITHM_MIGRATIONS[primaryAlgorithms.hashAlgorithm].supportedUntil
    else:
      dateTime(2030, mDec, 31)

  CompatibilityLayer(
    primaryAlgorithms: primaryAlgorithms,
    fallbackAlgorithms: fallbackAlgorithms,
    verificationStrategy: TryPrimaryThenFallback,
    migrationDeadline: migrationDeadline
  )

proc validateCompatibilityLayer*(layer: CompatibilityLayer): seq[string] =
  ## Validate compatibility layer configuration
  var warnings: seq[string] = @[]

  # Check if primary algorithms are quantum-resistant
  if not isQuantumResistant(layer.primaryAlgorithms):
    warnings.add("Primary algorithms are not quantum-resistant")

  # Check for deprecated fallback algorithms
  for fallback in layer.fallbackAlgorithms:
    let hashStatus = getMigrationStatus(fallback.hashAlgorithm)
    let sigStatus = getMigrationStatus(fallback.signatureAlgorithm)

    if hashStatus == Deprecated:
      warnings.add("Fallback hash algorithm " & fallback.hashAlgorithm & " is deprecated")
    if sigStatus == Deprecated:
      warnings.add("Fallback signature algorithm " & fallback.signatureAlgorithm & " is deprecated")

  # Check migration deadline
  if layer.migrationDeadline < now():
    warnings.add("Migration deadline has passed")

  return warnings

# =============================================================================
# Package Format Algorithm Upgrade Procedures
# =============================================================================

proc upgradePackageAlgorithms*(packageFormat: PackageFormat,
                              currentAlgorithms: CryptoAlgorithms): Result[CryptoAlgorithms, string] =
  ## Upgrade algorithms for a specific package format
  try:
    var upgraded = currentAlgorithms
    let recommended = getRecommendedAlgorithms(currentAlgorithms)

    case packageFormat:
    of NprRecipe:
      # NPR recipes prefer BLAKE2b for compatibility, but can use quantum-resistant
      if not isQuantumResistant(upgraded):
        upgraded.hashAlgorithm = "BLAKE3"
        upgraded.signatureAlgorithm = "Dilithium"
        upgraded.version = "2.0"

    of NpkBinary:
      # NPK packages prefer BLAKE3/Dilithium for security
      upgraded = recommended

    of NcaChunk:
      # NCA chunks use BLAKE3 for Merkle trees
      upgraded.hashAlgorithm = "BLAKE3"
      if not isQuantumResistant(upgraded.signatureAlgorithm):
        upgraded.signatureAlgorithm = "Dilithium"
        upgraded.version = "2.0"

    of NssSnapshot:
      # Snapshots need maximum security
      upgraded = recommended

    of NofOverlay:
      # Overlays prefer compatibility but support quantum-resistant
      if getMigrationStatus(upgraded.hashAlgorithm) in [PhaseOut, Deprecated]:
        upgraded = recommended

    return ok[CryptoAlgorithms, string](upgraded)

  except Exception as e:
    return err[CryptoAlgorithms, string]("Failed to upgrade algorithms: " & e.msg)

# =============================================================================
# Algorithm Transition Reporting
# =============================================================================

proc createTransitionReport*(packages: seq[CryptoAlgorithms]): JsonNode =
  ## Create comprehensive transition report
  var algorithmCounts: Table[string, int] = initTable[string, int]()
  var statusCounts: Table[MigrationStatus, int] = initTable[MigrationStatus, int]()
  var quantumReadyCount = 0

  for algorithms in packages:
    let algoKey = algorithms.hashAlgorithm & "/" & algorithms.signatureAlgorithm
    algorithmCounts[algoKey] = algorithmCounts.getOrDefault(algoKey, 0) + 1

    let hashStatus = getMigrationStatus(algorithms.hashAlgorithm)
    let sigStatus = getMigrationStatus(algorithms.signatureAlgorithm)
    let overallStatus = if hashStatus > sigStatus: hashStatus else: sigStatus

    statusCounts[overallStatus] = statusCounts.getOrDefault(overallStatus, 0) + 1

    if isQuantumResistant(algorithms):
      quantumReadyCount += 1

  let totalPackages = packages.len
  let quantumReadyPercent = if totalPackages > 0: (quantumReadyCount * 100) div totalPackages else: 0

  %*{
    "summary": {
      "total_packages": totalPackages,
      "quantum_ready": quantumReadyCount,
      "quantum_ready_percent": quantumReadyPercent,
      "migration_deadline": $QUANTUM_MIGRATION_TIMELINE.targetDate
    },
    "algorithm_usage": algorithmCounts,
    "migration_status": statusCounts,
    "recommendations": [
      if quantumReadyPercent < 50: "Prioritize quantum-resistant algorithm adoption" else: "",
      if statusCounts.getOrDefault(Deprecated, 0) > 0: "Immediately upgrade deprecated algorithms" else: "",
      if statusCounts.getOrDefault(PhaseOut, 0) > 0: "Plan migration for algorithms in phase-out" else: "",
      "Test quantum-resistant algorithms in development environment",
      "Implement gradual migration to avoid compatibility issues"
    ].filterIt(it.len > 0),
    "generated": $now()
  }

# =============================================================================
# Utility Functions
# =============================================================================

proc getDefaultQuantumAlgorithms*(): CryptoAlgorithms =
  ## Get default quantum-resistant algorithms
  CryptoAlgorithms(
    hashAlgorithm: "SHA3-512",
    signatureAlgorithm: "Dilithium",
    version: "2.0"
  )

proc getTransitionTimelineForAlgorithm*(algorithm: string): Option[AlgorithmMigration] =
  ## Get migration timeline for a specific algorithm
  for migration in QUANTUM_MIGRATION_TIMELINE.hashMigrations:
    if migration.fromAlgorithm == algorithm:
      return some(migration)

  for migration in QUANTUM_MIGRATION_TIMELINE.signatureMigrations:
    if migration.fromAlgorithm == algorithm:
      return some(migration)

  return none(AlgorithmMigration)

proc estimateMigrationEffort*(currentAlgorithms: CryptoAlgorithms,
                             targetAlgorithms: CryptoAlgorithms): MigrationComplexity =
  ## Estimate effort required for algorithm migration
  if currentAlgorithms.hashAlgorithm == targetAlgorithms.hashAlgorithm and
     currentAlgorithms.signatureAlgorithm == targetAlgorithms.signatureAlgorithm:
    return Simple

  let hashCompat = getAlgorithmCompatibility(currentAlgorithms.hashAlgorithm)
  let sigCompat = getAlgorithmCompatibility(currentAlgorithms.signatureAlgorithm)

  var maxComplexity = Simple

  if hashCompat.isSome and hashCompat.get().migrationComplexity > maxComplexity:
    maxComplexity = hashCompat.get().migrationComplexity

  if sigCompat.isSome and sigCompat.get().migrationComplexity > maxComplexity:
    maxComplexity = sigCompat.get().migrationComplexity

  return maxComplexity