<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Support\License\LicenseManager;
use App\Support\License\Updater;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Gate;

class SystemUpdaterController extends Controller
{
    protected LicenseManager $license;
    protected Updater $updater;

    public function __construct(LicenseManager $license, Updater $updater)
    {
        $this->license = $license;
        $this->updater = $updater;
    }

    public function updateServerForm()
    {
        Gate::authorize('system.update');
        $cacheKey = 'license_update_check';
        $cacheTtl = 60;
        $lastGoodKey = 'license_update_check_last_good';
        $lastGoodTtl = 3600;

        $currentVersion = $this->updater->getCurrentVersion();

        $cached = Cache::get($cacheKey);
        if ($cached !== null) {
            $cached['from_cache'] = true;
            $cached['license_activated'] = $this->isLicenseActivated();
            $cached['enable_oneclick_updater'] = config('license.enable_system_updater', true);
            return view('admin.settings.updater', $cached);
        }

        try {
            $checkUpdate = $this->updater->checkUpdate();
            $latestInfo = $this->updater->getLatestVersionInfo();

            $isRateLimited = empty($checkUpdate['status']) && (
                stripos($checkUpdate['message'] ?? '', 'too many') !== false ||
                stripos($checkUpdate['message'] ?? '', 'rate limit') !== false
            );

            if ($isRateLimited) {
                $lastGood = Cache::get($lastGoodKey);
                if ($lastGood) {
                    $lastGood['rate_limit_message'] = __('Update check is temporarily limited. Showing last result. Please try again in a minute.');
                    $lastGood['license_activated'] = $this->isLicenseActivated();
                    $lastGood['enable_oneclick_updater'] = config('license.enable_system_updater', true);
                    return view('admin.settings.updater', $lastGood);
                }
                $data = $this->buildUpdaterViewData($checkUpdate, $latestInfo, $currentVersion);
                $data['message'] = __('Too many attempts. Please try again in a minute.');
                $data['rate_limit_message'] = true;
                $data['license_activated'] = $this->isLicenseActivated();
                $data['enable_oneclick_updater'] = config('license.enable_system_updater', true);
                return view('admin.settings.updater', $data);
            }

            $data = $this->buildUpdaterViewData($checkUpdate, $latestInfo, $currentVersion);
            $data['license_activated'] = $this->isLicenseActivated();
            $data['enable_oneclick_updater'] = config('license.enable_system_updater', true);
            Cache::put($cacheKey, $data, $cacheTtl);
            Cache::put($lastGoodKey, $data, $lastGoodTtl);
            return view('admin.settings.updater', $data);
        } catch (\Exception $e) {
            $lastGood = Cache::get($lastGoodKey);
            if ($lastGood) {
                $lastGood['rate_limit_message'] = __('Could not check for updates. Showing last result.');
                $lastGood['license_activated'] = $this->isLicenseActivated();
                $lastGood['enable_oneclick_updater'] = config('license.enable_system_updater', true);
                return view('admin.settings.updater', $lastGood);
            }
            return back()->with('error', $e->getMessage());
        }
    }

    protected function buildUpdaterViewData(array $checkUpdate, array $latestInfo, ?string $currentVersion): array
    {
        $updateAvailable = ! empty($checkUpdate['update_available']);
        $latestVersion = $checkUpdate['version'] ?? ($latestInfo['data']['version'] ?? $currentVersion);
        $changelog = $checkUpdate['changelog'] ?? ($latestInfo['data']['changelog'] ?? null);
        $releaseDate = $checkUpdate['release_date'] ?? ($latestInfo['data']['released_at'] ?? null);
        $updateId = $checkUpdate['update_id'] ?? ($latestInfo['data']['update_id'] ?? null);
        $hasSql = ! empty($checkUpdate['has_sql']) || ! empty($latestInfo['data']['has_sql']);

        $fromSettings = function_exists('settingHelper') ? Updater::normalizeVersion((string) (settingHelper('version_code') ?? '')) : '';
        $versionCode = $currentVersion ?  $currentVersion : ($fromSettings !== '' ?  $fromSettings : '');
        $nextVersionCode = $latestVersion ?  $latestVersion : $versionCode;
        $versionCode = $fromSettings !== '' ?  $fromSettings : $versionCode;

        return [
            'response' => $checkUpdate,
            'latest_version' => $currentVersion,
            'current_version' => $currentVersion,
            'version_code' => $versionCode,
            'is_old' => $updateAvailable,
            'next_version' => $latestVersion,
            'next_version_code' => $nextVersionCode,
            'changelog' => $changelog,
            'changelog_plain' => Updater::stripChangelogHtml($changelog),
            'release_date' => $releaseDate,
            'update_id' => $updateId,
            'has_sql' => $hasSql,
            'message' => $checkUpdate['message'] ?? null,
            'enable_oneclick_updater' => config('license.enable_system_updater', true),
        ];
    }

    protected function isLicenseActivated(): bool
    {
        $licPath = config('license.license_file_path');
        if ($licPath && is_file($licPath) && filesize($licPath) > 0) {
            return true;
        }
        if (function_exists('settingHelper')) {
            $purchaseCode = settingHelper('purchase_code');
            if ($purchaseCode !== null && $purchaseCode !== '') {
                return true;
            }
            $activationCode = settingHelper('activation_code');
            if ($activationCode !== null && $activationCode !== '') {
                return true;
            }
        }
        return false;
    }

    public function downloadUpdate(Request $request): JsonResponse
    {
        Gate::authorize('system.update');
        try {
            if (config('app.demo_mode')) {
                return response()->json([
                    'message' => __('This function is disabled in demo server.'),
                    'type' => __('Error') . ' !',
                    'class' => 'danger',
                ]);
            }

            $updateId = $request->input('version_id');
            if (! $updateId) {
                return response()->json([
                    'message' => __('Update ID is required.'),
                    'type' => __('Error') . ' !',
                    'class' => 'danger',
                ]);
            }
            $versionFromServer = $request->input('version');

            $result = $this->updater->runUpdate((string) $updateId, $versionFromServer ?: null);

            if (! $result['success']) {
                return response()->json([
                    'message' => $result['message'],
                    'type' => __('Error') . ' !',
                    'class' => 'danger',
                ]);
            }

            return response()->json([
                'type' => __('Success') . ' !',
                'class' => 'success',
                'message' => $result['message'],
                'version' => $result['version'] ?? null,
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'type' => __('Error') . ' !',
                'class' => 'danger',
                'message' => $e->getMessage(),
            ]);
        }
    }

    public function runManualUpdateStep(Request $request): JsonResponse
    {
        Gate::authorize('system.update');
        if (config('app.demo_mode')) {
            return response()->json(['message' => __('This function is disabled in demo server.'), 'class' => 'danger']);
        }

        $step = (int) $request->input('step', 0);
        if ($step < 1 || $step > 6) {
            return response()->json(['message' => __('Invalid step.'), 'class' => 'danger']);
        }

        try {
            if ($step === 1) {
                $updateId = $request->input('version_id');
                if (! $updateId) {
                    return response()->json(['message' => __('Update ID is required for step 1.'), 'class' => 'danger']);
                }
                $result = $this->updater->downloadOnly((string) $updateId);
            } elseif ($step === 2) {
                $versionFromServer = $request->input('version');
                $result = $this->updater->extractOnly($versionFromServer ?: null);
            } elseif (in_array($step, [3, 4, 5, 6], true)) {
                $markerPath = Updater::manualExtractDoneMarkerPath();
                if ($step !== 6 && ! is_file($markerPath)) {
                    return response()->json([
                        'class' => 'danger',
                        'message' => __('Please run the previous steps in order. Run step 2 first.'),
                    ]);
                }
                if ($step === 3) {
                    Artisan::call('migrate', ['--force' => true]);
                    $result = ['success' => true, 'message' => __('Databases updated.')];
                } elseif ($step === 4) {
                    try {
                        Artisan::call('vendor:publish', ['--tag' => 'core-assets', '--force' => true]);
                    } catch (\Throwable $e) {
                    }
                    $result = ['success' => true, 'message' => __('Core assets published.')];
                } elseif ($step === 5) {
                    try {
                        Artisan::call('vendor:publish', ['--tag' => 'package-assets', '--force' => true]);
                    } catch (\Throwable $e) {
                    }
                    $result = ['success' => true, 'message' => __('Packages assets published.')];
                } else {
                    $zipPath = Updater::updaterZipPath();
                    if (file_exists($zipPath)) {
                        @unlink($zipPath);
                    }
                    if (file_exists($markerPath)) {
                        @unlink($markerPath);
                    }
                    if (class_exists(\App\Console\Commands\AllClear::class)) {
                        Artisan::call('all:clear');
                    } else {
                        Artisan::call('config:clear');
                        Artisan::call('cache:clear');
                        Artisan::call('view:clear');
                    }
                    $result = ['success' => true, 'message' => __('System update files cleaned up.')];
                }
            } else {
                $result = ['success' => false, 'message' => __('Invalid step.')];
            }

            $ok = ! empty($result['success']);
            return response()->json([
                'class' => $ok ? 'success' : 'danger',
                'message' => $result['message'] ?? ($ok ? __('Done.') : __('Step failed.')),
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'class' => 'danger',
                'message' => $e->getMessage(),
            ]);
        }
    }
}
