## Resolution Engine for NexusForge
## Implements the hierarchical package resolution DAG walker
## Priority: User > Native > Foreign > Git > Graft
##
## For Graft resolution, this module delegates to the existing GraftCoordinator
## which already has adapters for Nix, Pacman, PKGSRC, and AUR.

import std/[tables, options, algorithm, sequtils, json, strutils, os]
import ./config
import ../../nip/types
import ../types/grafting_types
import ../graft_coordinator
import ../install_manager
import ../adapters/git

type
  ResolutionContext* = object
    ## Context for package resolution
    query*: string
    repos*: seq[RepoConfig]
    userOverrides*: Table[string, Fragment]
    constraints*: seq[string]  # Version constraints, etc.

  ResolutionResult* = object
    ## Result of package resolution
    found*: bool
    source*: RepoConfig
    packageName*: string
    version*: string
    cid*: string  # Content ID (hash)

proc sortReposByPriority*(repos: seq[RepoConfig]): seq[RepoConfig] =
  ## Sort repositories by priority (highest first)
  result = repos.sorted(proc(a, b: RepoConfig): int =
    cmp(b.priority, a.priority)
  )

proc initResolutionContext*(query: string, repos: seq[RepoConfig]): ResolutionContext =
  ## Initialize a resolution context
  result = ResolutionContext(
    query: query,
    repos: sortReposByPriority(repos),
    userOverrides: initTable[string, Fragment](),
    constraints: @[]
  )

proc addUserOverride*(ctx: var ResolutionContext, packageName: string, fragment: Fragment) =
  ## Add a user-defined override for a package
  ctx.userOverrides[packageName] = fragment

proc checkUserOverride*(ctx: ResolutionContext): Option[ResolutionResult] =
  ## Check if user has defined an override for this package
  if ctx.userOverrides.hasKey(ctx.query):
    let fragment = ctx.userOverrides[ctx.query]
    return some(ResolutionResult(
      found: true,
      source: RepoConfig(name: "user-override", kind: Native, priority: 1000),
      packageName: fragment.id.name,
      version: fragment.id.version,
      cid: fragment.source.hash
    ))
  return none(ResolutionResult)

proc resolveFromNative*(ctx: ResolutionContext, repo: RepoConfig): Option[ResolutionResult] =
  ## Resolve package from a native repository
  ## TODO: Implement actual HTTP query to repo manifest
  return none(ResolutionResult)

proc resolveFromGit*(ctx: ResolutionContext, repo: RepoConfig): Option[ResolutionResult] =
  ## Resolve package from a git repository
  ## Polls tags and matches against semver patterns
  
  # Parse the git URL from repo config
  let sourceResult = parseGitUrl(repo.url)
  if not sourceResult.isOk:
    return none(ResolutionResult)
  
  var source = sourceResult.value
  source.token = repo.token
  if repo.branch.len > 0:
    source.branch = repo.branch
  
  # Fetch tags from the git source
  let tagsResult = fetchTags(source)
  if not tagsResult.isOk:
    return none(ResolutionResult)
  
  let tags = tagsResult.value
  if tags.len == 0:
    return none(ResolutionResult)
  
  # Filter tags by pattern (from constraints or default "*")
  let pattern = if ctx.constraints.len > 0: ctx.constraints[0] else: source.tagPattern
  let matchedTags = filterTags(tags, pattern)
  
  if matchedTags.len == 0:
    return none(ResolutionResult)
  
  # Take the newest matching tag
  let bestTag = matchedTags[0]
  
  return some(ResolutionResult(
    found: true,
    source: repo,
    packageName: source.repo,  # Use repo name as package name
    version: bestTag.name,
    cid: "git:" & source.owner & "/" & source.repo & "@" & bestTag.commit
  ))

proc resolveFromGraft*(ctx: ResolutionContext, repo: RepoConfig): Option[ResolutionResult] =
  ## Resolve package from a graft backend using the existing GraftCoordinator
  ## Supports: Nix, Pacman, PKGSRC, AUR
  
  # Map RepoConfig.backend to GraftSource
  let graftSource = case repo.backend:
    of Nix: GraftSource.Nix
    of Pacman: GraftSource.Pacman
    of Pkgsrc: GraftSource.PKGSRC
    # AUR is not in GraftBackend enum yet, but GraftCoordinator supports it
    else: GraftSource.Auto
  
  # Create a coordinator for this query using default config
  let coordinator = newGraftCoordinator(defaultConfig(), verbose = false)
  
  # Use auto-detection if source not explicitly mapped
  let result = coordinator.graft(ctx.query, graftSource)
  
  if result.success:
    return some(ResolutionResult(
      found: true,
      source: repo,
      packageName: result.packageName,
      version: result.version,
      cid: "graft:" & result.source & ":" & result.packageName & ":" & result.version
    ))
  
  return none(ResolutionResult)

proc resolvePackage*(ctx: ResolutionContext): ResolutionResult =
  ## Resolve a package through the hierarchy
  ## Priority: User Override > Native > Git > Graft
  
  # 1. Check user overrides first
  let userResult = ctx.checkUserOverride()
  if userResult.isSome:
    return userResult.get()
  
  # 2. Walk through repos by priority
  for repo in ctx.repos:
    let result = case repo.kind:
      of Native:
        ctx.resolveFromNative(repo)
      of Git:
        ctx.resolveFromGit(repo)
      of Graft:
        ctx.resolveFromGraft(repo)
    
    if result.isSome:
      return result.get()
  
  # 3. Not found anywhere
  return ResolutionResult(
    found: false,
    packageName: ctx.query
  )

proc formatResolutionTrace*(ctx: ResolutionContext, res: ResolutionResult): string =
  ## Format a human-readable resolution trace
  result = "Resolution trace for: " & ctx.query & "\n"
  
  if res.found:
    result &= "✅ FOUND in: " & res.source.name & " (" & $res.source.kind & ")\n"
    result &= "   Package: " & res.packageName & "\n"
    result &= "   Version: " & res.version & "\n"
    result &= "   CID: " & res.cid & "\n"
  else:
    result &= "❌ NOT FOUND\n"
    result &= "Searched:\n"
    for repo in ctx.repos:
      result &= "  - " & repo.name & " (" & $repo.kind & ", priority: " & $repo.priority & ")\n"
