<?php

/**
 * =============================================================================
 * MODPACK VERSION CHECKER - API SERVICE
 * =============================================================================
 * 
 * Centralized service for all modpack platform API interactions.
 * Used by both the Controller (manual checks) and Command (cron checks).
 * 
 * SUPPORTED PLATFORMS:
 * - Modrinth: Public API with User-Agent requirement
 * - CurseForge: Requires API key (configured in admin panel)
 * - FTB: Public API via modpacks.ch
 * - Technic: Public API with dynamic build number caching
 * 
 * WHY A SERVICE?
 * DRY principle - both the manual check button and the cron job need
 * the same API logic. Centralizing it here means:
 * - One place to fix bugs
 * - One place to add new platforms
 * - Consistent error handling
 * - Shared caching (e.g., Technic build number)
 * 
 * @package     Pterodactyl\BlueprintFramework\Extensions\modpackchecker
 * @author      Firefrost Gaming / Frostystyle <dev@firefrostgaming.com>
 * @version     1.0.0
 * =============================================================================
 */

namespace Pterodactyl\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
use Pterodactyl\BlueprintFramework\Libraries\ExtensionLibrary\Admin\BlueprintAdminLibrary as BlueprintExtensionLibrary;
use Exception;

class ModpackApiService
{
    public function __construct(
        private BlueprintExtensionLibrary $blueprint
    ) {}

    /**
     * Fetch the latest version info for a modpack from its platform API.
     * 
     * @param  string  $platform   Platform name: modrinth, curseforge, ftb, technic
     * @param  string  $modpackId  Platform-specific modpack identifier
     * @return array               Contains: name, version
     * @throws Exception           If platform unknown or API call fails
     */
    public function fetchLatestVersion(string $platform, string $modpackId): array
    {
        return match($platform) {
            'modrinth' => $this->checkModrinth($modpackId),
            'curseforge' => $this->checkCurseForge($modpackId),
            'ftb' => $this->checkFTB($modpackId),
            'technic' => $this->checkTechnic($modpackId),
            default => throw new Exception("Unknown platform: {$platform}")
        };
    }

    /**
     * Query Modrinth API for latest modpack version.
     * 
     * NO API KEY REQUIRED - uses User-Agent for identification.
     * Rate limit: 300 requests/minute (generous)
     * 
     * @param  string  $projectId  Modrinth project ID or slug
     * @return array               Contains: name, version
     * @throws Exception           If API request fails
     */
    private function checkModrinth(string $projectId): array
    {
        $headers = ['User-Agent' => 'FirefrostGaming/ModpackChecker/1.0'];
        
        $response = Http::timeout(10)->withHeaders($headers)
            ->get("https://api.modrinth.com/v2/project/{$projectId}");

        if (!$response->successful()) {
            throw new Exception('Modrinth API request failed: ' . $response->status());
        }

        $project = $response->json();

        $versionResponse = Http::timeout(10)->withHeaders($headers)
            ->get("https://api.modrinth.com/v2/project/{$projectId}/version");
            
        if (!$versionResponse->successful()) {
            throw new Exception('Modrinth versions API failed: ' . $versionResponse->status());
        }
        
        $versions = $versionResponse->json();

        $latestVer = $versions[0] ?? null;

        return [
            'name' => $project['title'] ?? 'Unknown',
            'version' => $latestVer['version_number'] ?? 'Unknown',
            'file_id' => $latestVer ? ($latestVer['id'] ?? null) : null,
        ];
    }

    /**
     * Query CurseForge API for latest modpack version.
     * 
     * REQUIRES API KEY - configured in admin panel.
     * Rate limit: ~1000 requests/day for personal keys.
     * 
     * @param  string  $modpackId  CurseForge project ID (numeric)
     * @return array               Contains: name, version
     * @throws Exception           If API key missing or request fails
     */
    private function checkCurseForge(string $modpackId): array
    {
        $apiKey = trim($this->blueprint->dbGet('modpackchecker', 'curseforge_api_key') ?? '');

        if (empty($apiKey)) {
            throw new Exception('CurseForge API key not configured');
        }

        \Log::debug('[MVC] CurseForge API call — key length: ' . strlen($apiKey) . ', modpack: ' . $modpackId);

        $response = Http::timeout(10)->withHeaders([
            'x-api-key' => $apiKey,
            'Accept' => 'application/json',
        ])->get("https://api.curseforge.com/v1/mods/{$modpackId}");

        if (!$response->successful()) {
            throw new Exception('CurseForge API request failed: ' . $response->status());
        }
        
        $data = $response->json()['data'] ?? [];
        $latestFile = $data['latestFiles'][0] ?? null;

        // Extract clean version from displayName (e.g. "All the Mods 9-0.1.0" → "0.1.0")
        $displayName = $latestFile['displayName'] ?? 'Unknown';
        $cleanVersion = $displayName;
        if (preg_match('/[\d]+\.[\d]+\.[\d]+/', $displayName, $matches)) {
            $cleanVersion = $matches[0];
        }

        return [
            'name' => $data['name'] ?? 'Unknown',
            'version' => $cleanVersion,
            'display_name' => $displayName,
            'file_id' => $latestFile ? (string) $latestFile['id'] : null,
        ];
    }

    /**
     * Query Feed The Beast (FTB) API for latest modpack version.
     * 
     * NO API KEY REQUIRED - modpacks.ch is public.
     * 
     * @param  string  $modpackId  FTB modpack ID (numeric)
     * @return array               Contains: name, version
     * @throws Exception           If API request fails
     */
    private function checkFTB(string $modpackId): array
    {
        $response = Http::timeout(10)->get("https://api.modpacks.ch/public/modpack/{$modpackId}");
        
        if (!$response->successful()) {
            throw new Exception('FTB API request failed: ' . $response->status());
        }
        
        $data = $response->json();

        $latestVer = $data['versions'][0] ?? null;

        return [
            'name' => $data['name'] ?? 'Unknown',
            'version' => $latestVer['name'] ?? 'Unknown',
            'file_id' => $latestVer ? (string) ($latestVer['id'] ?? null) : null,
        ];
    }

    /**
     * Fetch file/version history for date-time seeding.
     * Returns array of ['file_id', 'version', 'display_name', 'release_date'].
     */
    public function fetchFileHistory(string $platform, string $modpackId, int $limit = 20): array
    {
        return match($platform) {
            'curseforge' => $this->fetchCurseForgeHistory($modpackId, $limit),
            'modrinth' => $this->fetchModrinthHistory($modpackId, $limit),
            'ftb' => $this->fetchFtbHistory($modpackId, $limit),
            default => []
        };
    }

    private function fetchCurseForgeHistory(string $modpackId, int $limit): array
    {
        $apiKey = trim($this->blueprint->dbGet('modpackchecker', 'curseforge_api_key') ?? '');
        if (empty($apiKey)) return [];

        $response = Http::timeout(15)->withHeaders([
            'x-api-key' => $apiKey,
            'Accept' => 'application/json',
        ])->get("https://api.curseforge.com/v1/mods/{$modpackId}/files", [
            'pageSize' => $limit,
        ]);

        if (!$response->successful()) return [];

        return collect($response->json()['data'] ?? [])
            ->map(fn($f) => [
                'file_id' => (string) $f['id'],
                'version' => $f['displayName'] ?? 'Unknown',
                'display_name' => $f['displayName'] ?? 'Unknown',
                'release_date' => $f['fileDate'] ?? null,
            ])
            ->toArray();
    }

    private function fetchModrinthHistory(string $projectId, int $limit): array
    {
        $response = Http::timeout(15)
            ->withHeaders(['User-Agent' => 'FirefrostGaming/ModpackChecker/1.0'])
            ->get("https://api.modrinth.com/v2/project/{$projectId}/version");

        if (!$response->successful()) return [];

        return collect($response->json() ?? [])
            ->take($limit)
            ->map(fn($v) => [
                'file_id' => $v['id'] ?? null,
                'version' => $v['version_number'] ?? 'Unknown',
                'display_name' => $v['name'] ?? $v['version_number'] ?? 'Unknown',
                'release_date' => $v['date_published'] ?? null,
            ])
            ->toArray();
    }

    private function fetchFtbHistory(string $modpackId, int $limit): array
    {
        $response = Http::timeout(15)
            ->get("https://api.modpacks.ch/public/modpack/{$modpackId}");

        if (!$response->successful()) return [];

        return collect($response->json()['versions'] ?? [])
            ->take($limit)
            ->map(fn($v) => [
                'file_id' => (string) ($v['id'] ?? ''),
                'version' => $v['name'] ?? 'Unknown',
                'display_name' => $v['name'] ?? 'Unknown',
                'release_date' => isset($v['updated']) ? date('c', $v['updated']) : null,
            ])
            ->toArray();
    }

    /**
     * Query Technic Platform API for latest modpack version.
     * 
     * NO API KEY REQUIRED - but requires dynamic build number.
     * The build number is cached for 12 hours to reduce API calls.
     * 
     * "RV-Ready" approach: Technic blocks old build numbers, so we
     * dynamically fetch the current stable launcher build.
     * 
     * @param  string  $slug  Technic modpack slug (URL-friendly name)
     * @return array          Contains: name, version
     * @throws Exception      If API request fails
     */
    private function checkTechnic(string $slug): array
    {
        // Cache the build number for 12 hours to prevent rate limits
        $latestBuild = Cache::remember('modpackchecker_technic_build', 43200, function () {
            $versionResponse = Http::timeout(10)->get('https://api.technicpack.net/launcher/version/stable4');
            return $versionResponse->successful() 
                ? ($versionResponse->json('build') ?? 999) 
                : 999;
        });
        
        $response = Http::timeout(10)->withHeaders([
            'User-Agent' => 'FirefrostGaming/ModpackChecker/1.0',
            'Accept' => 'application/json',
        ])->get("https://api.technicpack.net/modpack/{$slug}?build={$latestBuild}");

        if (!$response->successful()) {
            throw new Exception('Technic API request failed: ' . $response->status());
        }
        
        $data = $response->json();

        return [
            'name' => $data['displayName'] ?? $data['name'] ?? 'Unknown',
            'version' => $data['version'] ?? 'Unknown',
            'file_id' => $data['version'] ?? null,
        ];
    }
}
