src/Models/Settings.ps1

# Settings — Preferencias del usuario serializables a JSON.
# Reemplaza el `UserPreferences` con 11 sub-modelos del v2 (ADR-003).
# Forma plana: una sola clase, propiedades simples.

class Settings {
    # Apariencia
    [string]   $ThemeKey = 'midnight'
    [string]   $Language = 'es'             # 'es' | 'en'
    [bool]     $ShowAliases = $true
    [bool]     $ShowTags = $true
    [bool]     $ShowLastCommit = $true

    # Paths
    [string]   $ReposPath                   # raíz donde escanea
    [string[]] $AdditionalPaths = @()       # paths extra opcionales
    [string[]] $HiddenRepoIds = @()         # repos ocultados manualmente

    # Aliases del usuario: id → @{ alias='', color='c5' }
    [hashtable] $RepoAliases = @{}

    # Timestamp del último fetch exitoso por repo: id → ISO string.
    # Se actualiza después de pull/fetch/push exitoso. La UI lo lee para mostrar
    # "(fetch hace 12 min)" como hint sutil — el user sabe que el ahead/behind
    # puede estar desactualizado y no se confunde.
    [hashtable] $LastFetchByRepo = @{}

    # Favoritos
    [string[]] $FavoriteIds = @()
    # Si on, los favoritos se renderean primero en la lista del MainScreen
    # (manteniendo orden alfabético adentro de cada grupo). Off = orden original
    # del discovery (alfabético plano).
    [bool]     $FavoritesFirst = $false

    # Git
    [int]      $GitCacheTtlSeconds = 30
    [bool]     $AutoFetch = $false
    # BackgroundFetchInterval: cada cuántos segundos correr 'git fetch --quiet'
    # en los repos visibles, en background, sin bloquear la UI. 0 = off (default).
    # Sugerencias: 300 (5min), 600 (10min), 1800 (30min). ConfigScreen cyclea
    # entre estos valores.
    [int]      $BackgroundFetchInterval = 0
    # AutoLoadMode controla cuántos repos cargan git status al boot:
    # 'All' → todos los visibles (default — UX más rico)
    # 'Favorites' → solo los repos en FavoriteIds; el resto on-demand
    # 'None' → ninguno; user pulsa R o navega para cargar
    # Útil para usuarios con muchos repos o red lenta. ConfigScreen lo
    # expone como cycle, init lo pregunta interactivo.
    [string]   $AutoLoadMode = 'All'

    # UI
    [bool]     $UseAlternateBuffer = $true  # entrar en alt screen
    [int]      $RefreshDebounceMs = 200

    Settings() { }

    [bool] IsFavorite([string]$repoId) {
        return $this.FavoriteIds -contains $repoId
    }

    [bool] IsHidden([string]$repoId) {
        return $this.HiddenRepoIds -contains $repoId
    }

    [hashtable] GetAlias([string]$repoId) {
        return $this.RepoAliases[$repoId]
    }

    [bool] HasAlias([string]$repoId) {
        if ([string]::IsNullOrWhiteSpace($repoId)) { return $false }
        return $this.RepoAliases.ContainsKey($repoId)
    }

    [void] SetAlias([string]$repoId, [string]$alias, [string]$color) {
        if ([string]::IsNullOrWhiteSpace($repoId)) { return }
        if ([string]::IsNullOrWhiteSpace($alias)) { return }
        $this.RepoAliases[$repoId] = @{
            alias = $alias.Trim()
            color = $color
        }
    }

    [void] RemoveAlias([string]$repoId) {
        if ([string]::IsNullOrWhiteSpace($repoId)) { return }
        if ($this.RepoAliases.ContainsKey($repoId)) {
            $this.RepoAliases.Remove($repoId)
        }
    }

    # Marca "fetcheamos este repo recién" — se llama después de un fetch/pull/push
    # exitoso. Usa ISO 8601 UTC para que sea estable cross-timezone.
    [void] RecordFetch([string]$repoId) {
        if ([string]::IsNullOrWhiteSpace($repoId)) { return }
        $this.LastFetchByRepo[$repoId] = [DateTime]::UtcNow.ToString('o')
    }

    # Devuelve $null si nunca se fetcheó, sino [DateTime] UTC.
    [object] GetLastFetch([string]$repoId) {
        if ([string]::IsNullOrWhiteSpace($repoId)) { return $null }
        $iso = $this.LastFetchByRepo[$repoId]
        if (-not $iso) { return $null }
        try {
            return [DateTime]::Parse($iso, [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::RoundtripKind)
        } catch {
            return $null
        }
    }
}