<?php

namespace App\Http\Controllers\Settings;

use App\Http\Controllers\Controller;
use App\Models\Branch;
use App\Models\Dealer;
use App\Models\DealerDocument;
use App\Support\BranchCodeGenerator;
use App\Services\DealerProvisioningService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\View\View;

class DealerController extends Controller
{
    public function index(): View
    {
        $dealers = Dealer::query()
            ->orderByDesc('is_default')
            ->orderBy('name')
            ->paginate(20);

        $deletedDealers = Dealer::onlyTrashed()
            ->orderBy('name')
            ->get();

        return view('settings.dealers.index', compact('dealers', 'deletedDealers'));
    }

    public function create(): View
    {
        return view('settings.dealers.create');
    }

    public function store(Request $request, DealerProvisioningService $provisioningService): RedirectResponse
    {
        $normalizedDomain = strtolower(trim((string) $request->input('domain', '')));
        $normalizedDefaultBranchName = trim((string) $request->input('default_branch_name', ''));
        $normalizedDefaultBranchAddress = trim((string) $request->input('default_branch_address', ''));
        $normalizedBusinessReg = strtoupper(trim((string) $request->input('business_registration_number', '')));
        $rawVat = trim((string) $request->input('vat_number', ''));
        // Remove any non-digits for VAT input (spaces/hyphens), then validate normalized form.
        $normalizedVat = preg_replace('/\D+/', '', $rawVat);

        $request->merge([
            'domain' => $normalizedDomain,
            'default_branch_name' => $normalizedDefaultBranchName,
            'default_branch_address' => $normalizedDefaultBranchAddress,
            'business_registration_number' => $normalizedBusinessReg,
            'vat_number' => $normalizedVat,
        ]);

        $data = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'domain' => [
                'required',
                'string',
                'max:255',
                'regex:/^[a-z0-9.-]+\.[a-z]{2,}$/i',
                'unique:dealers,domain',
            ],
            'business_registration_number' => ['nullable', 'string', 'max:100', 'regex:/^(?:\d{4}\/\d{6}\/\d{2}|K\d{10})$/'],
            'vat_number' => ['nullable', 'string', 'regex:/^\d{10}$/'],
            'dealer_address' => ['nullable', 'string', 'max:255'],
            'telephone' => ['nullable', 'string', 'max:50'],
            'contact_email' => ['nullable', 'email', 'max:255'],
            'main_contact_name' => ['nullable', 'string', 'max:255'],
            'main_contact_cell' => ['nullable', 'string', 'max:50'],
            'main_contact_email' => ['nullable', 'email', 'max:255'],
            'default_branch_name' => ['required', 'string', 'max:255'],
            'default_branch_address' => ['required', 'string', 'max:255'],
            'nav_color' => ['required', 'string', 'regex:/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/'],
            'accent_color' => ['required', 'string', 'regex:/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/'],
            'accent_color_2' => ['required', 'string', 'regex:/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/'],
            'background_color' => ['required', 'string', 'regex:/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/'],
            'topbar_color' => ['required', 'string', 'regex:/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/'],
            'logo' => ['nullable', 'image', 'max:2048'],
            'favicon' => [
                'nullable',
                'file',
                'mimetypes:image/x-icon,image/vnd.microsoft.icon,image/png,image/svg+xml',
                'max:512',
            ],
            'login_background' => ['nullable', 'image', 'max:3072'],
            'login_logo' => ['nullable', 'image', 'max:2048'],
            'login_accent_color' => ['nullable', 'string', 'regex:/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/'],
            'cipc_documents' => ['nullable', 'array'],
            'cipc_documents.*' => ['file', 'mimes:pdf,jpg,jpeg,png,webp,bmp,doc,docx', 'max:10240'],
            'vat_certificate' => ['nullable', 'file', 'mimes:pdf,jpg,jpeg,png,webp,bmp,doc,docx', 'max:10240'],
            'proof_of_address' => ['nullable', 'file', 'mimes:pdf,jpg,jpeg,png,webp,bmp,doc,docx', 'max:10240'],
        ], [
            'business_registration_number.regex' => 'Business Registration Number must be in a valid CIPC format, e.g. 2020/123456/07 or K2020123456.',
            'vat_number.regex' => 'VAT Number must be exactly 10 digits.',
        ]);

        $slug = strtoupper(Str::slug($data['name'], '-'));
        $base = $slug !== '' ? 'DLR-'.$slug : 'DLR-DEALER';
        $code = $base;
        $suffix = 2;

        while (Dealer::query()->where('code', $code)->exists()) {
            $code = $base.'-'.$suffix;
            $suffix++;
        }

        // Handle branding uploads before the transaction; paths are saved on the new dealer.
        $logoPath = null;
        $faviconPath = null;
        $loginBackgroundPath = null;
        $loginLogoPath = null;

        if ($request->hasFile('logo')) {
            $logoPath = $request->file('logo')->store('dealer-logos', ['disk' => 'public']);
        }

        if ($request->hasFile('favicon')) {
            $faviconPath = $request->file('favicon')->store('dealer-favicons', ['disk' => 'public']);
        }

        if ($request->hasFile('login_background')) {
            $loginBackgroundPath = $request->file('login_background')->store('dealer-login-backgrounds', ['disk' => 'public']);
        }

        if ($request->hasFile('login_logo')) {
            $loginLogoPath = $request->file('login_logo')->store('dealer-login-logos', ['disk' => 'public']);
        }

        DB::transaction(function () use (&$dealer, $data, $code, $logoPath, $faviconPath, $loginBackgroundPath, $loginLogoPath, $request): void {
            // Intentionally avoid mass-assignment for immutable fields (code/is_default)
            // so they can't be changed via request payloads elsewhere.
            $dealer = new Dealer();
            $dealer->name = $data['name'];
            $dealer->domain = $data['domain'];
            $dealer->business_registration_number = $data['business_registration_number'] ?? null;
            $dealer->vat_number = $data['vat_number'] ?? null;
            $dealer->address = $data['dealer_address'] ?? null;
            $dealer->telephone = $data['telephone'] ?? null;
            $dealer->contact_email = $data['contact_email'] ?? null;
            $dealer->main_contact_name = $data['main_contact_name'] ?? null;
            $dealer->main_contact_cell = $data['main_contact_cell'] ?? null;
            $dealer->main_contact_email = $data['main_contact_email'] ?? null;
            $dealer->code = $code;
            $dealer->is_default = false;
            $dealer->is_active = true;
            $dealer->provisioning_status = 'pending';
            $dealer->nav_color = $data['nav_color'];
            $dealer->accent_color = $data['accent_color'];
            $dealer->accent_color_2 = $data['accent_color_2'];
            $dealer->background_color = $data['background_color'];
            $dealer->topbar_color = $data['topbar_color'];
            if ($logoPath) {
                $dealer->logo_path = $logoPath;
            }
            if ($faviconPath) {
                $dealer->favicon_path = $faviconPath;
            }
            if ($loginBackgroundPath) {
                $dealer->login_background_path = $loginBackgroundPath;
            }
            if ($loginLogoPath) {
                $dealer->login_logo_path = $loginLogoPath;
            }
            if (! empty($data['login_accent_color'])) {
                $dealer->login_accent_color = $data['login_accent_color'];
            }
            $dealer->save();

            $hasAnyBranch = Branch::withoutGlobalScope('dealer_scope')
                ->where('dealer_id', $dealer->id)
                ->exists();

            if (! $hasAnyBranch) {
                $branch = new Branch();
                $branch->dealer_id = $dealer->id;
                $branch->name = $data['default_branch_name'];
                $branch->address = $data['default_branch_address'];
                $branch->code = BranchCodeGenerator::nextForDealer($dealer);
                $branch->is_default = true;
                $branch->is_active = true;
                $branch->save();
            }

            // Dealer documents
            $docDisk = 'public';
            $baseDir = 'dealer-documents/'.$dealer->id;

            if ($request->hasFile('cipc_documents')) {
                foreach ($request->file('cipc_documents') as $file) {
                    if (! $file) {
                        continue;
                    }

                    $storedPath = $file->store($baseDir.'/cipc', ['disk' => $docDisk]);

                    DealerDocument::create([
                        'dealer_id' => $dealer->id,
                        'document_type' => 'cipc',
                        'original_name' => $file->getClientOriginalName(),
                        'file_path' => $storedPath,
                        'mime_type' => $file->getClientMimeType(),
                        'file_size' => $file->getSize(),
                    ]);
                }
            }

            if ($request->hasFile('vat_certificate')) {
                $file = $request->file('vat_certificate');
                $storedPath = $file->store($baseDir.'/vat', ['disk' => $docDisk]);

                DealerDocument::create([
                    'dealer_id' => $dealer->id,
                    'document_type' => 'vat_certificate',
                    'original_name' => $file->getClientOriginalName(),
                    'file_path' => $storedPath,
                    'mime_type' => $file->getClientMimeType(),
                    'file_size' => $file->getSize(),
                ]);
            }

            if ($request->hasFile('proof_of_address')) {
                $file = $request->file('proof_of_address');
                $storedPath = $file->store($baseDir.'/proof-of-address', ['disk' => $docDisk]);

                DealerDocument::create([
                    'dealer_id' => $dealer->id,
                    'document_type' => 'proof_of_address',
                    'original_name' => $file->getClientOriginalName(),
                    'file_path' => $storedPath,
                    'mime_type' => $file->getClientMimeType(),
                    'file_size' => $file->getSize(),
                ]);
            }
        });

        // Provision baseline departments, roles and permissions for this dealer.
        // Keep dealer even if provisioning fails; status will reflect failure.
        try {
            $summary = $provisioningService->provision($dealer, [
                'include_passwords' => true,
                'run_type' => 'create',
                'triggered_by_user_id' => auth()->id(),
            ]);
        } catch (\Throwable $e) {
            // Surface a generic error while detailed message is stored on the dealer.
            return redirect()
                ->route('settings.dealers.index')
                ->withErrors(['provisioning' => 'Dealer was created but baseline provisioning failed. Check provisioning status for details.']);
        }

        return redirect()
            ->route('settings.dealers.provisioning-summary', $dealer)
            ->with('status', 'Dealer created and provisioned successfully.')
            ->with('provisioning_summary', $summary ?? null);
    }

    public function edit(Dealer $dealer): View
    {
        return view('settings.dealers.edit', compact('dealer'));
    }

    public function show(Dealer $dealer): View
    {
        $dealer->load(['documents' => function ($query) {
            $query->orderBy('created_at', 'desc');
        }]);

        return view('settings.dealers.show', compact('dealer'));
    }

    public function update(Request $request, Dealer $dealer): RedirectResponse
    {
        $data = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'is_active' => ['sometimes', 'boolean'],
            'domain' => [
                'sometimes',
                'string',
                'max:255',
                'regex:/^[a-z0-9.-]+\.[a-z]{2,}$/i',
                'unique:dealers,domain,'.$dealer->id,
            ],
        ]);

        $isActive = array_key_exists('is_active', $data)
            ? (bool) $data['is_active']
            : (bool) $dealer->is_active;

        if (array_key_exists('domain', $data)) {
            $normalizedDomain = strtolower(trim($data['domain']));

            if (
                ($dealer->provisioned_at !== null || $dealer->provisioning_status === 'provisioned')
                && $normalizedDomain !== strtolower((string) $dealer->domain)
            ) {
                abort(403, 'Domain cannot be changed after provisioning.');
            }

            $data['domain'] = $normalizedDomain;
        }

        if ($dealer->is_default && !$isActive) {
            return back()
                ->withErrors(['is_active' => 'The default dealer cannot be deactivated.'])
                ->withInput();
        }

        DB::transaction(function () use ($dealer, $data, $isActive): void {
            $dealer->name = $data['name'];
            $dealer->is_active = $isActive;
            if (array_key_exists('domain', $data)) {
                $dealer->domain = $data['domain'];
            }
            $dealer->save();
        });

        return redirect()
            ->route('settings.dealers.index')
            ->with('status', 'Dealer updated successfully.');
    }

    public function toggleActive(Dealer $dealer): RedirectResponse
    {
        if ($dealer->is_default) {
            return back()->withErrors(['is_active' => 'The default dealer cannot be deactivated.']);
        }

        $dealer->is_active = !$dealer->is_active;
        $dealer->save();

        return back()->with('status', 'Dealer status updated.');
    }

    public function showDocument(Dealer $dealer, DealerDocument $document)
    {
        if ($document->dealer_id !== $dealer->id) {
            abort(404);
        }

        $path = $document->file_path;

        if (! Storage::disk('public')->exists($path)) {
            abort(404);
        }

        // Use asset() for host-agnostic public URLs (matches other branding assets).
        $url = asset('storage/'.$path);

        return redirect()->away($url);
    }

    public function destroy(Dealer $dealer): RedirectResponse
    {
        if ($dealer->is_default) {
            return back()->withErrors(['delete' => 'The default dealer cannot be deleted.']);
        }

        $dealer->delete();

        return redirect()
            ->route('settings.dealers.index')
            ->with('status', 'Dealer deleted.');
    }

    public function restore(int $dealer): RedirectResponse
    {
        $dealerModel = Dealer::withTrashed()->findOrFail($dealer);

        if (! $dealerModel->trashed()) {
            return back()->with('status', 'Dealer is not deleted.');
        }

        $dealerModel->restore();

        return back()->with('status', 'Dealer restored.');
    }

    public function provisioningSummary(Dealer $dealer): View
    {
        $summary = session('provisioning_summary');

        return view('settings.dealers.provisioning-summary', [
            'dealer' => $dealer,
            'summary' => $summary,
        ]);
    }

    public function reprovision(Dealer $dealer, DealerProvisioningService $provisioningService): RedirectResponse
    {
        // Provision baseline again for the default dealer. Idempotent and does not reset existing passwords.
        try {
            $summary = $provisioningService->provision($dealer, [
                'include_passwords' => false,
                'run_type' => 'reprovision',
                'triggered_by_user_id' => auth()->id(),
            ]);
        } catch (\Throwable $e) {
            return redirect()
                ->route('settings.dealers.index')
                ->withErrors(['provisioning' => 'Dealer reprovisioning failed. Check provisioning status for details.']);
        }

        return redirect()
            ->route('settings.dealers.provisioning-summary', $dealer)
            ->with('status', 'Dealer reprovisioned successfully.')
            ->with('provisioning_summary', $summary ?? null);
    }
}

