<?php

namespace App\Controllers\Install;

use App\Controllers\BaseController;
use App\Services\Install\DatabaseConnectionTester;
use App\Services\Install\FolderPermissionChecker;
use App\Services\Install\InstallRunner;
use App\Services\Install\InstallSession;
use App\Services\Install\ServerRequirementChecker;
use App\Services\Install\SmtpTester;

class InstallController extends BaseController
{
    private InstallSession $wizard;

    public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
    {
        parent::initController($request, $response, $logger);
        $this->wizard = new InstallSession();
    }

    // ------------------------------------------------------------------
    // STEP 1 — Server Requirement Check
    // ------------------------------------------------------------------
    public function step1()
    {
        $checker = new ServerRequirementChecker();
        $results = $checker->check();

        if ($this->request->getMethod() === 'post') {
            if (! $checker->allPassed()) {
                return $this->jsonError([['code' => 'REQUIREMENTS_NOT_MET', 'message' => 'Server does not meet minimum requirements.']], 400);
            }
            $this->wizard->markStepComplete(1);
            return $this->jsonSuccess(['next' => base_url('install/step/2')]);
        }

        return view('install/step1_requirements', ['results' => $results, 'allPassed' => $checker->allPassed()]);
    }

    // ------------------------------------------------------------------
    // STEP 2 — Folder Permission Check
    // ------------------------------------------------------------------
    public function step2()
    {
        $this->guardStep(2);

        $checker = new FolderPermissionChecker();
        $results = $checker->check();

        if ($this->request->getMethod() === 'post') {
            if (! $checker->allPassed()) {
                return $this->jsonError([['code' => 'PERMISSIONS_NOT_MET', 'message' => 'Some folders are not writable.']], 400);
            }
            $this->wizard->markStepComplete(2);
            return $this->jsonSuccess(['next' => base_url('install/step/3')]);
        }

        return view('install/step2_permissions', ['results' => $results, 'allPassed' => $checker->allPassed()]);
    }

    // ------------------------------------------------------------------
    // STEP 3 — Database Configuration
    // ------------------------------------------------------------------
    public function step3()
    {
        $this->guardStep(3);

        if ($this->request->getMethod() === 'post') {
            $input = $this->request->getPost();

            $rules = [
                'host'     => 'required',
                'port'     => 'required|numeric',
                'database' => 'required|alpha_dash',
                'username' => 'required',
            ];
            if (! $this->validateData($input, $rules)) {
                return $this->jsonValidationError($this->validator->getErrors());
            }

            $this->wizard->set('step3', $input);
            $this->wizard->markStepComplete(3);
            return $this->jsonSuccess(['next' => base_url('install/step/4')]);
        }

        return view('install/step3_database');
    }

    public function testDatabaseConnection()
    {
        $input = $this->request->getJSON(true);
        $tester = new DatabaseConnectionTester();

        $result = $tester->test(
            $input['host'] ?? '',
            $input['port'] ?? '3306',
            $input['database'] ?? '',
            $input['username'] ?? '',
            $input['password'] ?? ''
        );

        return $result['success']
            ? $this->jsonSuccess(['message' => $result['message']])
            : $this->jsonError([['code' => 'DB_CONNECTION_FAILED', 'message' => $result['message']]], 400);
    }

    // ------------------------------------------------------------------
    // STEP 4 — Application Configuration
    // ------------------------------------------------------------------
    public function step4()
    {
        $this->guardStep(4);

        if ($this->request->getMethod() === 'post') {
            $input = $this->request->getPost();

            $rules = [
                'app_name' => 'required|min_length[2]',
                'app_url'  => 'required|valid_url_strict',
                'timezone' => 'required',
                'locale'   => 'required|in_list[en,ur]',
                'currency' => 'required|alpha|exact_length[3]',
            ];
            if (! $this->validateData($input, $rules)) {
                return $this->jsonValidationError($this->validator->getErrors());
            }

            $this->wizard->set('step4', $input);
            $this->wizard->markStepComplete(4);
            return $this->jsonSuccess(['next' => base_url('install/step/5')]);
        }

        return view('install/step4_application', ['timezones' => \DateTimeZone::listIdentifiers()]);
    }

    // ------------------------------------------------------------------
    // STEP 5 — Admin Account Creation
    // ------------------------------------------------------------------
    public function step5()
    {
        $this->guardStep(5);

        if ($this->request->getMethod() === 'post') {
            $input = $this->request->getPost();

            $rules = [
                'name'                  => 'required|min_length[2]',
                'email'                 => 'required|valid_email',
                'password'              => 'required|min_length[10]',
                'password_confirmation' => 'required|matches[password]',
            ];
            if (! $this->validateData($input, $rules)) {
                return $this->jsonValidationError($this->validator->getErrors());
            }

            $this->wizard->set('step5', $input);
            $this->wizard->markStepComplete(5);
            return $this->jsonSuccess(['next' => base_url('install/step/6')]);
        }

        return view('install/step5_admin_account');
    }

    // ------------------------------------------------------------------
    // STEP 6 — SMTP Configuration (optional, skippable)
    // ------------------------------------------------------------------
    public function step6()
    {
        $this->guardStep(6);

        if ($this->request->getMethod() === 'post') {
            $input = $this->request->getPost();

            if (($input['skip'] ?? '0') === '1') {
                $this->wizard->set('step6', []);
                $this->wizard->markStepComplete(6);
                return $this->jsonSuccess(['next' => base_url('install/step/7')]);
            }

            $rules = [
                'host'       => 'required',
                'port'       => 'required|numeric',
                'username'   => 'required',
                'from_email' => 'required|valid_email',
            ];
            if (! $this->validateData($input, $rules)) {
                return $this->jsonValidationError($this->validator->getErrors());
            }

            $this->wizard->set('step6', $input);
            $this->wizard->markStepComplete(6);
            return $this->jsonSuccess(['next' => base_url('install/step/7')]);
        }

        return view('install/step6_smtp');
    }

    public function testSmtp()
    {
        $input = $this->request->getJSON(true);
        $tester = new SmtpTester();
        $result = $tester->sendTest($input, $input['test_recipient'] ?? $input['from_email'] ?? '');

        return $result['success']
            ? $this->jsonSuccess(['message' => $result['message']])
            : $this->jsonError([['code' => 'SMTP_TEST_FAILED', 'message' => $result['message']]], 400);
    }

    // ------------------------------------------------------------------
    // STEP 7 — Payment Configuration (optional, skippable)
    // ------------------------------------------------------------------
    public function step7()
    {
        $this->guardStep(7);

        if ($this->request->getMethod() === 'post') {
            $input = $this->request->getPost();
            $this->wizard->set('step7', $input); // all fields optional — trial/billing-disabled mode if left blank
            $this->wizard->markStepComplete(7);
            return $this->jsonSuccess(['next' => base_url('install/step/8')]);
        }

        return view('install/step7_payment');
    }

    // ------------------------------------------------------------------
    // STEP 8 — Install Application (progress-bar driven, one AJAX call per step)
    // ------------------------------------------------------------------
    public function step8()
    {
        $this->guardStep(8);
        return view('install/step8_run', ['steps' => InstallRunner::STEPS]);
    }

    public function runStep(string $step)
    {
        if (! array_key_exists($step, InstallRunner::STEPS)) {
            return $this->jsonError([['code' => 'INVALID_STEP', 'message' => "Unknown step: {$step}"]], 400);
        }

        $runner = new InstallRunner();
        $result = $runner->runStep($step, $this->wizard->all());

        if ($result['success'] && $step === 'write_lock') {
            $this->wizard->clear();
        }

        return $result['success']
            ? $this->jsonSuccess(['message' => $result['message']])
            : $this->jsonError([['code' => 'INSTALL_STEP_FAILED', 'message' => $result['message']]], 500);
    }

    // ------------------------------------------------------------------
    // Post-install cron self-test
    // ------------------------------------------------------------------
    public function verifyCron()
    {
        $marker = WRITEPATH . 'cron_last_run.txt';

        if (! file_exists($marker)) {
            return $this->jsonError([['code' => 'CRON_NOT_DETECTED', 'message' => 'No cron execution detected yet. It may take up to a minute after adding the crontab entry.']], 404);
        }

        $lastRun = trim(file_get_contents($marker));
        $minutesAgo = (time() - strtotime($lastRun)) / 60;

        return $minutesAgo <= 5
            ? $this->jsonSuccess(['message' => "Cron is running. Last execution: {$lastRun}."])
            : $this->jsonError([['code' => 'CRON_STALE', 'message' => "Last cron execution was {$lastRun} — check your crontab entry."]], 400);
    }

    // ------------------------------------------------------------------
    private function guardStep(int $step): void
    {
        if (! $this->wizard->isStepComplete($step - 1) && $step > 1) {
            // Soft guard: redirect back rather than hard-fail, so refreshing
            // mid-wizard doesn't strand the admin (idempotent-friendly UX).
            // base_url() (not a hardcoded absolute path) so this works
            // whether the app lives at the domain root or a subfolder
            // like /portal/public/.
            header('Location: ' . base_url('install/step/' . max(1, $this->wizard->highestCompletedStep() + 1)));
            exit;
        }
    }
}
