<?php

namespace Corbital\Installer\Classes;

// use Illuminate\Support\Facades\Config;
// use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Corbital\Installer\Classes\EnvironmentManager;

use ZipArchive;

class UpdateChecker
{
    public $url;

    public function __construct()
    {
        $environment = new EnvironmentManager;
        $this->url   = $environment->guessUrl();
    }

    public function installVersion($data)
    {
        // Always set the license settings during installation
        set_settings_batch('whats-mark', [
            'wm_version'            => config('installer.license_verification.current_version'),
            'wm_verification_id'    => base64_encode($data['verification_id']),
            'wm_verification_token' => base64_encode($data['verification_id']) . '|' . $data['token'],
            'wm_last_verification'  => now()->timestamp,
            'wm_support_until'      => $data['support_until'],
            'wm_validate'           => true,
        ]);
    }

    public function checkUpdate($token, $mode = 'install')
    {
        return [
            'success' => false, // No update available
            'message' => 'No updates available at the moment (Bypassed).',
        ];
    }

    public function downloadUpdate(
        string $updateId,
        bool $needsSqlUpdate,
        string $version,
        string $token,
        ?string $license = null,
        ?string $client = null,
        ?string $mode = 'install'
    ) {
        try {
            $mainFile = $this->downloadFile('main', $updateId, $version, $token, $license, $client);

            if (isset($mainFile['success'])) {
                return [
                    'success' => false,
                    'message' => $mainFile['message'],
                ];
            }
            $this->extractUpdate($mainFile, 'main', $mode);

            if ($needsSqlUpdate) {
                $sqlFile = $this->downloadFile('sql', $updateId, $version, $token, $license, $client);
                $this->extractUpdate($sqlFile, 'sql', $mode);
            }

            return [
                'success' => true,
                'message' => 'Update completed',
            ];
        } catch (\Throwable $e) {

            Log::error('Update failed: ' . $e->getMessage());

            return [
                'success' => false,
                'message' => $e->getMessage(),
            ];
        }
    }

    private function downloadFile(string $type, string $updateId, string $version, string $token, ?string $license, ?string $client)
    {
        $destination = config('installer.license_verification.root_path') . "/update_{$type}_{$version}.zip";

        if (! is_dir(dirname($destination))) {
            mkdir(dirname($destination), 0755, true);
        }

        $response = Http::timeout(60)
            ->withHeaders([
                'Accept'        => 'application/json',
                'Authorization' => 'Bearer ' . $token,
            ])
            ->sink($destination)
            ->post(rtrim(base64_decode(config('installer.license_verification.api_endpoint')), '/') . "/download-update/$type/$updateId", [
                'license_code'     => $license,
                'client_name'      => $client,
                'activated_domain' => $this->url,
            ]);

        $responseData = $response->json();

        // If validation failed
        if (isset($responseData['success']) && $responseData['success'] != true) {
            $errorMessages = $responseData['errors'] ?? [$responseData['message'] ?? 'License validation failed'];

            if (is_array($errorMessages) && isset($errorMessages['license_code'])) {
                return [
                    'success' => $response['success'],
                    'message' => $errorMessages['license_code'][0],
                ];
            }

            return [
                'success' => $response['success'],
                'message' => $response['message'],
            ];
        }

        return $destination;
    }

    private function extractUpdate(string $zipFile, string $type, string $mode): void
    {
        $zip = new ZipArchive;

        if ($zip->open($zipFile) !== true) {
            throw new \RuntimeException('Failed to open update file');
        }

        // Define extraction path
        $extractPath = base_path();

        // Ensure directory exists
        if (! File::exists($extractPath)) {
            File::makeDirectory($extractPath, 0755, true);
        }

        // Extract ZIP file
        $zip->extractTo($extractPath);
        $zip->close();

        // Delete the original ZIP file after extraction
        File::delete($zipFile);

        // Handle SQL type (extract and import SQL)
        if ($type === 'sql') {
            $this->importSQLFromExtractedFiles($extractPath);
            if ($mode != 'install') {
                Artisan::call('db:seed', ['--force' => true]);
                Artisan::call('migrate', ['--force' => true]);
            }
        }
    }

    /**
     * Check for SQL file and import it into the database.
     */
    private function importSQLFromExtractedFiles(string $extractPath): void
    {
        $sqlFile = null;

        // Search for an SQL file in the extracted directory
        foreach (scandir($extractPath) as $file) {
            if (pathinfo($file, PATHINFO_EXTENSION) === 'sql') {
                $sqlFile = $extractPath . '/' . $file;
                break;
            }
        }

        if (! $sqlFile) {
            throw new \RuntimeException('No SQL file found in extracted update.');
        }

        // Read and execute the SQL file
        try {
            $sql = file_get_contents($sqlFile);
            DB::statement('SET FOREIGN_KEY_CHECKS=0');
            DB::unprepared($sql);
            DB::statement('SET FOREIGN_KEY_CHECKS=1');

            // Delete SQL file after successful import
            File::delete($sqlFile);

        } catch (\Exception $e) {
            throw new \RuntimeException('SQL import failed: ' . $e->getMessage());
        }
    }

    public function checkSupportExpiryStatus($supportedUntil = '')
    {
        return [
            'success'     => true,
            'type'        => 'success',
            'message'     => "Support is active (Bypassed).",
            'time_diff'   => "Unlimited left",
            'support_url' => trim(base64_decode(config('installer.license_verification.support_url'))),
        ];
    }

    public function getVersionLog()
    {
        return [
            'success' => true,
            'data'    => [],
        ];
    }

    public function validateRequest()
    {
        return true;
    }
}
