<?php

namespace App\Http\Controllers\Install;

use App\Http\Controllers\Controller;
use App\Models\Branch;
use App\Models\Company;
use App\Models\FiscalYear;
use App\Models\Role;
use App\Models\User;
use Database\Seeders\FoundationSeeder;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\View\View;
use Throwable;

final class InstallerController extends Controller
{
    public function index(): View|RedirectResponse
    {
        if ($this->isInstalled()) {
            return redirect()->route('login');
        }

        return view('install.index', [
            'requirements' => $this->requirements(),
            'writable' => $this->writableDirectories(),
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        abort_if($this->isInstalled(), 404);

        $data = $request->validate([
            'legal_name' => ['required', 'string', 'max:200'],
            'trade_name' => ['nullable', 'string', 'max:200'],
            'trn' => ['nullable', 'string', 'max:20'],
            'trade_license_number' => ['nullable', 'string', 'max:100'],
            'company_email' => ['nullable', 'email', 'max:150'],
            'company_phone' => ['nullable', 'string', 'max:60'],
            'address' => ['nullable', 'string', 'max:3000'],
            'website' => ['nullable', 'url', 'max:250'],
            'logo' => ['nullable', 'image', 'mimes:png,jpg,jpeg,webp', 'max:2048'],
            'financial_year_start_month' => ['required', 'integer', 'between:1,12'],
            'vat_registered' => ['nullable', 'boolean'],
            'vat_registration_date' => ['nullable', 'date'],
            'branch_code' => ['required', 'alpha_dash', 'max:20'],
            'branch_name' => ['required', 'string', 'max:150'],
            'branch_emirate' => ['nullable', 'string', 'max:100'],
            'admin_name' => ['required', 'string', 'max:150'],
            'admin_email' => ['required', 'email', 'max:190'],
            'admin_password' => ['required', 'string', 'min:10', 'confirmed'],
        ]);

        $failed = collect($this->requirements())->contains(false)
            || collect($this->writableDirectories())->contains(false);
        if ($failed) {
            return back()->withInput()->with('error', 'Server requirements are not satisfied. Review the checklist below.');
        }

        try {
            DB::connection()->getPdo();
            Artisan::call('migrate', ['--force' => true]);
            app(FoundationSeeder::class)->run();

            $logoPath = $request->hasFile('logo') ? $request->file('logo')->store('company', 'public') : null;

            DB::transaction(function () use ($data, $request, $logoPath): void {
                $company = Company::query()->firstOrFail();
                $company->update([
                    'legal_name' => $data['legal_name'],
                    'trade_name' => $data['trade_name'] ?: $data['legal_name'],
                    'trn' => $data['trn'] ?: null,
                    'trade_license_number' => $data['trade_license_number'] ?: null,
                    'email' => $data['company_email'] ?: null,
                    'phone' => $data['company_phone'] ?: null,
                    'address' => $data['address'] ?: null,
                    'website' => $data['website'] ?: null,
                    'logo_path' => $logoPath,
                    'financial_year_start_month' => $data['financial_year_start_month'],
                    'vat_registered' => $request->boolean('vat_registered'),
                    'vat_registration_date' => $data['vat_registration_date'] ?: null,
                    'base_currency' => 'AED',
                    'timezone' => 'Asia/Dubai',
                    'setup_completed_at' => now(),
                    'is_active' => true,
                ]);

                $branch = Branch::query()->where('company_id', $company->id)->oldest('id')->firstOrFail();
                $branch->update([
                    'code' => strtoupper($data['branch_code']),
                    'name' => $data['branch_name'],
                    'emirate' => $data['branch_emirate'] ?: null,
                    'address' => $data['address'] ?: null,
                    'email' => $data['company_email'] ?: null,
                    'phone' => $data['company_phone'] ?: null,
                    'is_active' => true,
                ]);

                $admin = User::query()->updateOrCreate(
                    ['email' => strtolower($data['admin_email'])],
                    [
                        'company_id' => $company->id,
                        'branch_id' => null,
                        'name' => $data['admin_name'],
                        'password' => Hash::make($data['admin_password']),
                        'is_active' => true,
                        'email_verified_at' => now(),
                    ],
                );
                $role = Role::query()->where('company_id', $company->id)->where('slug', 'super-administrator')->firstOrFail();
                $admin->roles()->sync([$role->id]);
            });

            // Rebuild the empty fiscal calendar using the selected financial-year month.
            FiscalYear::query()->where('company_id', Company::query()->value('id'))->delete();
            app(FoundationSeeder::class)->run();

            File::ensureDirectoryExists(storage_path('app'));
            File::put(storage_path('app/installed'), json_encode([
                'installed_at' => now()->toIso8601String(),
                'version' => trim((string) @file_get_contents(base_path('VERSION'))) ?: '1.0.0',
                'installation_id' => (string) Str::uuid(),
            ], JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));

            Artisan::call('optimize:clear');
            return redirect()->route('login')->with('success', 'Installation completed. Sign in with the administrator account.');
        } catch (Throwable $exception) {
            report($exception);
            return back()->withInput()->with('error', 'Installation failed: '.$exception->getMessage().' Check the database settings in .env and retry.');
        }
    }

    /** @return array<string,bool> */
    private function requirements(): array
    {
        return [
            'PHP 8.4 or newer' => version_compare(PHP_VERSION, '8.4.0', '>='),
            'BCMath extension' => extension_loaded('bcmath'),
            'Ctype extension' => extension_loaded('ctype'),
            'cURL extension' => extension_loaded('curl'),
            'DOM extension' => extension_loaded('dom'),
            'Fileinfo extension' => extension_loaded('fileinfo'),
            'JSON extension' => extension_loaded('json'),
            'Mbstring extension' => extension_loaded('mbstring'),
            'OpenSSL extension' => extension_loaded('openssl'),
            'PDO extension' => extension_loaded('pdo'),
            'PDO MySQL extension' => extension_loaded('pdo_mysql'),
            'Tokenizer extension' => extension_loaded('tokenizer'),
            'XML extension' => extension_loaded('xml'),
        ];
    }

    /** @return array<string,bool> */
    private function writableDirectories(): array
    {
        return [
            'storage directory' => is_writable(storage_path()),
            'bootstrap/cache directory' => is_writable(base_path('bootstrap/cache')),
        ];
    }

    private function isInstalled(): bool
    {
        return file_exists(storage_path('app/installed'));
    }
}
