<?php

namespace App\Http\Controllers;

use App\Http\Requests\InstallRequest;
use App\Models\Config;
use App\Models\User;
use App\Support\License\Installer;
use App\Support\License\LicenseManager;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\URL;
use ZipArchive;

class InstallController extends Controller
{
    protected LicenseManager $license;
    protected Installer $installer;

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

    public function index()
    {

        return view('install.index');
    }

    /**
     * Single-step install: validate DB, activate license, run migrations and seed (license server integration).
     */
    public function getInstall(InstallRequest $request): JsonResponse
    {
        ini_set('max_execution_time', 900);
        $host = $request->host;
        $db_user = $request->db_user;
        $db_name = $request->db_name;
        $db_password = $request->db_password;
        $first_name = $request->first_name;
        $last_name = $request->last_name;
        $email = $request->email;
        $login_password = $request->password;
        $client_name = $request->client_name ?? '';
        $purchase_code = $request->purchase_code ?? '';

        $socket = null;
        if ($host === 'localhost' || $host === '127.0.0.1') {
            $common_sockets = [
                '/Applications/MAMP/tmp/mysql/mysql.sock',
                '/Applications/XAMPP/xamppfiles/var/mysql/mysql.sock',
                '/tmp/mysql.sock',
                '/var/mysql/mysql.sock',
            ];
            foreach ($common_sockets as $path) {
                if (file_exists($path)) {
                    $socket = $path;
                    break;
                }
            }
        }

        try {
            $mysqli = @new \mysqli($host, $db_user, $db_password, $db_name, null, $socket);
            if ($mysqli->connect_error) {
                return response()->json(['error' => __('Database connection failed: ') . $mysqli->connect_error]);
            }
        } catch (\Exception $e) {
            return response()->json(['error' => __('Database connection failed: ') . $e->getMessage()]);
        }
        $mysqli->close();

        $activate = $this->installer->activateAndWriteLicense($purchase_code, $client_name);
        if (! $activate['success']) {
            return response()->json(['error' => $activate['message']]);
        }

        session()->put('email', $email);
        session()->put('first_name', $first_name);
        session()->put('last_name', $last_name);
        session()->put('login_password', $login_password);
        session()->put('purchase_code', $purchase_code);
        session()->put('client_name', $client_name);

        $dbConfig = [
            'DB_HOST' => $host,
            'DB_DATABASE' => $db_name,
            'DB_USERNAME' => $db_user,
            'DB_PASSWORD' => $db_password,
        ];
        if ($socket) {
            $dbConfig['DB_SOCKET'] = $socket;
        }

        $appUrl = rtrim($request->getSchemeAndHttpHost() . $request->getBaseUrl(), '/');

        try {
            $this->installer->runMigrationsAndSeed($dbConfig, $appUrl);
            $this->installer->runPostInstallCallbacks();
            try {
                Artisan::call('jwt:secret', ['--force' => true]);
            } catch (\Throwable $e) {
            }
            $this->demoDataImport();
        } catch (\Exception $e) {
            return response()->json([
                'error' => __('Installation failed.') . ' ' . $e->getMessage(),
                'route' => route('install.initialize'),
            ]);
        }

        return response()->json([
            'success' => __('Installation was successful.'),
            'route' => $appUrl,
        ]);
    }

    public function final(InstallRequest $request): JsonResponse
    {
        try {
            $zip_file = base_path('public/install/installer.zip');
            if (file_exists($zip_file)) {
                $zip = new ZipArchive;
                if ($zip->open($zip_file) === true) {
                    $zip->extractTo(base_path('/'));
                    $zip->close();
                } else {
                    return response()->json([
                        'type' => 'error',
                        'error' => 'Installation files Not Found, Please Try Again',
                        'route' => route('install.initialize'),
                    ]);
                }
                unlink($zip_file);
            }
            $config_file = base_path('config.json');
            if (file_exists($config_file)) {
                $config = json_decode(file_get_contents($config_file), true);
            } else {
                return response()->json([
                    'type' => 'error',
                    'error' => 'Config File Not Found, Please Try Again',
                    'route' => route('install.initialize'),
                ]);
            }
            Artisan::call('migrate:fresh', ['--force' => true, '--seed' => true]);
            // Generate JWT secret key
            Artisan::call('cache:clear');
            Artisan::call('config:clear');
            Artisan::call('route:clear');
            Artisan::call('view:clear');
            $this->dataInserts($config, $request);
            $this->envUpdates();
            $this->demoDataImport();

            return response()->json([
                'type' => 'success',
                'success' => 'Installation was Successful',
                'route' => url('/'),
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'error' => $e->getMessage(),
            ]);
        }
    }

    protected function dataInserts($config, $request): void
    {
        $user = User::find(1);
        $user->email = $request->email;
        $user->first_name = $request->first_name;
        $user->last_name = $request->last_name;
        $user->password = bcrypt($request->password);
        $user->save();

        $code = Config::where('title', 'activation_code')->first();

        if ($code) {
            $code->update([
                'value' => session()->get('activation_code'),
            ]);
        } else {
            Config::create([
                'title' => 'activation_code',
                'value' => session()->get('activation_code'),
            ]);
        }

        if (isAppMode()) {
            $version = $config['app_version'];
            $version_code = $config['app_version_code'];
        } else {
            $version = $config['web_version'];
            $version_code = $config['web_version_code'];
        }

        $code = Config::where('title', 'version_code')->first();
        $version_no = Config::where('title', 'current_version')->first();

        if ($code) {
            $code->update([
                'value' => $version_code,
            ]);
        } else {
            Config::create([
                'title' => 'version_code',
                'value' => $version_code,
            ]);
        }

        if ($version_no) {
            $version_no->update([
                'value' => $version,
            ]);
        } else {
            Config::create([
                'title' => 'current_version',
                'value' => $version,
            ]);
        }

        if (arrayCheck('removed_directories', $config)) {
            foreach ($config['removed_directories'] as $directory) {
                File::deleteDirectory(base_path($directory));
            }
        }
    }

    protected function envUpdates(): void
    {
        envWrite('APP_URL', URL::to('/'));
        Artisan::call('key:generate');
    }

    protected function demoDataImport(): void
    {
        try {
            DB::unprepared(file_get_contents(base_path('public/sql/demo_data.sql')));
        } catch (\Exception $e) {
            // non-fatal: demo data optional
        }
    }

    public function releaseForm()
    {
        if (!config('app.debug')) {
            abort(404);
        }

        return view('install.release');
    }

    public function createRelease(Request $request)
    {
        $request->validate([
            'latest_commit' => 'required',
            'old_commit' => 'required',
            'prefix' => 'required',
            'version' => 'required',
        ]);

        try {
            $latest_commit = $request->latest_commit;
            $old_commit = $request->old_commit;
            $name = $request->prefix;
            $version = $request->version;

            $gitBinary = config('app.git_binary');
            $gitDiffCommand = $gitBinary . " diff --name-only " . escapeshellarg($old_commit) . ' ' . escapeshellarg($latest_commit);
            $changedFiles = shell_exec($gitDiffCommand);
            if ($changedFiles === null || trim($changedFiles) === '') {
                throw new \Exception('No changed files between the two commits, or git command failed.');
            }

            $releaseCreatorPath = base_path('release_creator.txt');
            file_put_contents($releaseCreatorPath, $changedFiles);

            $lines = array_filter(array_map('trim', explode("\n", $changedFiles)));
            $files = array_values(array_unique($lines));

            $release_name = $name . '_release_v' . $version;
            $zip_file = base_path($release_name . '.zip');
            $zip = new ZipArchive;
            if ($zip->open($zip_file, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
                throw new \Exception('Could not create zip file: ' . $zip_file);
            }
            foreach ($files as $file) {
                $fullPath = base_path($file);
                if (file_exists($fullPath)) {
                    $zip->addFile($fullPath, $file);
                }
            }
            $zip->close();

            // Keep release_creator.txt and the zip; no deletions.
            return back()->with('success_message', 'Release Created Successfully');
        } catch (\Exception $e) {
            Log::info($e->getMessage());

            return back()->with('error_message', $e->getMessage())->withInput();
        }
    }

    /*
    // --- OLD createRelease (commented out) ---
    public function createRelease(Request $request)
    {
        $request->validate([
            'latest_commit' => 'required',
            'old_commit' => 'required',
            'prefix' => 'required',
            'version' => 'required',
        ]);

        try {
            $latest_commit = $request->latest_commit;
            $old_commit = $request->old_commit;
            $name = $request->prefix;
            $version = $request->version;
            $gitDiffCommand = "git diff --name-only $latest_commit $old_commit";
            $changedFiles = shell_exec($gitDiffCommand);
            file_put_contents(base_path('release_creator.txt'), $changedFiles);
            $file = base_path('release_creator.txt');
            $lines = file($file);
            $data = [];
            foreach ($lines as $line) {
                $data[] = $line;
            }
            $data = array_filter($data);
            $data = array_map('trim', $data);
            $data = array_filter(array_unique(array_values($data)));
            $zip = new ZipArchive;
            $release_name = $name . '_release_v' . $version;
            $zip_file = base_path("$release_name.zip");
            if ($zip->open($zip_file, ZipArchive::CREATE) === true) {
                foreach ($data as $file) {
                    if (file_exists(base_path($file))) {
                        $zip->addFile(base_path($file), $file);
                    }
                }
                $zip->close();
            }
            // $script_url = str_replace('admin/system-update', '', (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
            // $fields = [
            //     'domain' => urlencode($_SERVER['SERVER_NAME']),
            //     'version' => $request->latest_version,
            //     'item_id' => 59566505,
            //     'purchase_code' => urlencode(setting('activation_code')),
            //     'url' => urlencode($script_url),
            //     'is_beta' => config('app.dev_mode') ? 1 : 0,
            // ];
            // $_request = curlRequest('https://desk.spagreen.net/verify-installation-v2', $fields);
            // if (!is_object($_request)) {
            //     throw new \Exception('Invalid response from verification server. Please check your internet connection and try again.');
            // }

            // if (empty($_request->release_zip_link)) {
            //     $errorMessage = isset($_request->message) ? $_request->message : 'Missing release_zip_link in API response.';
            //     throw new \Exception($errorMessage);
            // }

           // $zip_file = $_request->release_zip_link;
            $file_path = base_path('updater.zip');
            $zipContent = file_get_contents($zip_file);
            if ($zipContent === false) {
                throw new \Exception('Failed to download release zip from: ' . $zip_file);
            }
            file_put_contents($file_path, $zipContent);
            File::delete([base_path('release_creator.txt'), $file_path]);

            return back()->with('success_message', 'Release Created Successfully');
        } catch (\Exception $e) {
            Log::info($e->getMessage());

            return back()->with('error_message', $e->getMessage())->withInput();
        }
    }
    */
}
