modules/Core/LegacyApiClient.psm1

# Legacy API Client Module
# Handles the simple token management and API invocation for the main Spotify CLI module.

# --- Private Module State ---
$script:AppDataDir = Join-Path $env:APPDATA "SpotifyCLI" # Duplicated from LegacyConfigManager, needs a better solution later.
$script:TokenFile = Join-Path $script:AppDataDir "tokens.json"
$script:TokenEndpoint = "https://accounts.spotify.com/api/token"
$script:ApiBase = "https://api.spotify.com/v1"
$script:RedirectUri = "http://127.0.0.1:8888/callback"
$script:Scopes = "user-read-playback-state user-modify-playback-state user-read-currently-playing user-read-private playlist-read-private user-library-read user-library-modify user-read-recently-played user-top-read"

# --- Public Functions ---

function Invoke-SpotifyApi {
    param(
        [Parameter(Mandatory)][ValidateSet('GET', 'POST', 'PUT', 'DELETE')][string]$Method,
        [Parameter(Mandatory)][string]$Path,
        [hashtable]$Query,
        $Body
    )
    $access = Get-SpotifyAccessToken
    if (-not $access) { return $null }
    # Build the complete URI
    $uri = "$($script:ApiBase)$path"
    if ($Query -and $Query.Count -gt 0) {
        $queryString = ($Query.GetEnumerator() | ForEach-Object {
            "$($_.Key)=$([System.Uri]::EscapeDataString($_.Value))"
        }) -join "&"
        $uri += "?$queryString"
    }
    $headers = @{ Authorization = "Bearer $access" }
    try {
        if ($Body) {
            return Invoke-RestMethod -Method $Method -Uri $uri -Headers $headers -ContentType "application/json" -Body ($Body | ConvertTo-Json -Depth 10)
        } else {
            return Invoke-RestMethod -Method $Method -Uri $uri -Headers $headers
        }
    } catch {
        $statusCode = 0
        if ($_.Exception.Response) {
            $statusCode = [int]$_.Exception.Response.StatusCode
        }

        $responseBody = ""
        if ($_.Exception.Response.GetResponseStream) {
            $streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
            $responseBody = $streamReader.ReadToEnd()
            $streamReader.Close()
        }

        switch ($statusCode) {
            401 {
                throw "Spotify API authentication failed. Token may be expired or invalid. (HTTP $statusCode)"
            }
            403 {
                $errorDetails = ($responseBody | ConvertFrom-Json -ErrorAction SilentlyContinue)
                $message = if ($errorDetails) { $errorDetails.error.message } else { "Permission denied. This operation may require a higher scope or Spotify Premium." }
                throw "$message (HTTP $statusCode)"
            }
            404 {
                throw "The requested resource was not found. (HTTP $statusCode)"
            }
            429 {
                $retryAfter = $_.Exception.Response.Headers['Retry-After']
                throw "Rate limited by Spotify. Retry after $retryAfter seconds. (HTTP $statusCode)"
            }
            default {
                throw "An unexpected Spotify API error occurred: $($_.Exception.Message) (HTTP $statusCode)"
            }
        }
    }
}

# --- Private Helper Functions ---

function Initialize-TokenStore {
    if (-not (Test-Path $script:AppDataDir)) {
        New-Item -ItemType Directory -Path $script:AppDataDir | Out-Null
    }
    if (-not (Test-Path $script:TokenFile)) {
        '{}' | Set-Content -Path $script:TokenFile -Encoding UTF8
    }
}

function Get-StoredTokens {
    Initialize-TokenStore
    try {
        $json = Get-Content -Path $script:TokenFile -Raw -ErrorAction Stop
        if ([string]::IsNullOrWhiteSpace($json)) { return @{} }
        return ($json | ConvertFrom-Json)
    } catch { return @{} }
}

function Set-StoredTokens($Tokens) {
    Initialize-TokenStore
    ($Tokens | ConvertTo-Json -Depth 5) | Set-Content -Path $script:TokenFile -Encoding UTF8
}

function Get-SpotifyAccessToken {
    $tokens = Get-StoredTokens
    if (-not $tokens.access_token) {
        Write-Host "🔐 Authentication required. Please run the main CLI script first to authenticate." -ForegroundColor Yellow
        Write-Host "Run: .\spotifyCLI.ps1" -ForegroundColor Cyan
        return $null
    }
    # Check if token has required scopes for enhanced features
    if (-not (Test-TokenScopes $tokens)) {
        Write-Host "🔐 Token requires additional permissions. Please re-authenticate using the main CLI script." -ForegroundColor Yellow
        Write-Host "Run: .\spotifyCLI.ps1" -ForegroundColor Cyan
        return $null
    }
    # Check if token is expired and refresh if needed
    $obtained = [long]$tokens.obtained_at
    $expiresIn = [int]$tokens.expires_in
    $age = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds() - $obtained
    if ($age -ge ($expiresIn - 60)) {
        # Token is expired, try to refresh
        if (-not $tokens.refresh_token) {
            Write-Host "🔐 Token expired and no refresh token available. Please re-authenticate." -ForegroundColor Yellow
            Write-Host "Run: .\spotifyCLI.ps1" -ForegroundColor Cyan
            return $null
        }
        try {
            $body = @{
                grant_type = "refresh_token"
                refresh_token = $tokens.refresh_token
                client_id = $env:SPOTIFY_CLIENT_ID
                client_secret = $env:SPOTIFY_CLIENT_SECRET
            }
            $tokenResp = Invoke-RestMethod -Method Post -Uri $script:TokenEndpoint -Body $body
            $tokens.access_token = $tokenResp.access_token
            if ($tokenResp.refresh_token) { $tokens.refresh_token = $tokenResp.refresh_token }
            $tokens.expires_in = $tokenResp.expires_in
            $tokens.obtained_at = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
            Set-StoredTokens $tokens
            Write-Host "🔄 Token refreshed successfully" -ForegroundColor Green
        } catch {
            Write-Host "🔄 Token refresh failed. Please re-authenticate." -ForegroundColor Red
            Write-Host "Run: .\spotifyCLI.ps1" -ForegroundColor Cyan
            return $null
        }
    }
    return $tokens.access_token
}

function Test-TokenScopes {
    <#
    .SYNOPSIS
    Test if current token has required scopes for enhanced features
    #>

    param($Tokens)
    # If no scope information is stored, assume old token and require re-auth
    if (-not $Tokens.scopes) {
        return $false
    }
    # Check if all required scopes are present
    $requiredScopes = $script:Scopes -split ' '
    $tokenScopes = $Tokens.scopes -split ' '
    foreach ($scope in $requiredScopes) {
        if ($scope -notin $tokenScopes) {
            Write-Verbose "Missing required scope: $scope"
            return $false
        }
    }
    return $true
}


function Test-SpotifyAuth {
    <#
    .SYNOPSIS
    Check the current Spotify authentication status
    .DESCRIPTION
    Reads the stored token file and reports whether authentication is valid,
    how long until expiry, and which scopes are granted.
    .EXAMPLE
    Test-SpotifyAuth
    #>

    $result = [PSCustomObject]@{
        IsAuthenticated  = $false
        ExpiresInSeconds = 0
        Scopes           = @()
        TokenPath        = $script:TokenFile
        Error            = $null
    }

    if (-not (Test-Path $script:TokenFile)) {
        $result.Error = "Token file not found. Run .\spotifyCLI.ps1 to authenticate."
        Write-Host "❌ Not authenticated — token file missing" -ForegroundColor Red
        Write-Host " Run: .\spotifyCLI.ps1" -ForegroundColor Cyan
        return $result
    }

    try {
        $tokens = Get-Content -Path $script:TokenFile -Raw | ConvertFrom-Json
    } catch {
        $result.Error = "Could not read token file: $_"
        Write-Host "❌ Token file is corrupt or unreadable" -ForegroundColor Red
        return $result
    }

    if (-not $tokens.access_token) {
        $result.Error = "No access token in token file."
        Write-Host "❌ Not authenticated — no access token stored" -ForegroundColor Red
        return $result
    }

    $obtained    = [long]$tokens.obtained_at
    $expiresIn   = [int]$tokens.expires_in
    $age         = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds() - $obtained
    $remaining   = $expiresIn - $age

    if ($remaining -le 0) {
        $result.Error = "Token has expired."
        Write-Host "❌ Token expired" -ForegroundColor Red
        if ($tokens.refresh_token) {
            Write-Host " A refresh token is available — run .\spotifyCLI.ps1 to refresh" -ForegroundColor Yellow
        }
        return $result
    }

    $result.IsAuthenticated  = $true
    $result.ExpiresInSeconds = [int]$remaining
    $result.Scopes           = if ($tokens.scopes) { $tokens.scopes -split ' ' } else { @() }

    $minutesLeft = [Math]::Floor($remaining / 60)
    Write-Host "✅ Authenticated" -ForegroundColor Green
    Write-Host " Token expires in: $minutesLeft minutes" -ForegroundColor Gray
    Write-Host " Scopes: $($result.Scopes.Count) granted" -ForegroundColor Gray
    Write-Host " Token file: $script:TokenFile" -ForegroundColor Gray

    return $result
}


# --- Module Exports ---

Export-ModuleMember -Function 'Invoke-SpotifyApi', 'Test-SpotifyAuth'