<?php

namespace App\Http\Controllers\Settings;

use App\Http\Controllers\Controller;
use App\Models\Dealer;
use App\Services\DealerProvisioningService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
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
    {
        $data = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'domain' => [
                'required',
                'string',
                'max:255',
                'regex:/^[a-z0-9.-]+\.[a-z]{2,}$/i',
                'unique:dealers,domain',
            ],
        ]);

        $data['domain'] = strtolower(trim($data['domain']));

        $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++;
        }

        DB::transaction(function () use (&$dealer, $data, $code): 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->code = $code;
            $dealer->is_default = false;
            $dealer->is_active = true;
            $dealer->provisioning_status = 'pending';
            $dealer->save();
        });

        // 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 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 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);
    }
}

