<?php

namespace App\Http\Controllers\Company\Masters;

use App\Http\Controllers\Controller;
use App\Models\{AuditLog, Currency, ExchangeRate};
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

class CurrenciesController extends Controller
{
    public function index()
    {
        $this->gate('settings', 'view');

        $companyId  = auth()->user()->company_id;

        $currencies = Currency::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->orderByDesc('is_base')
            ->orderBy('code')
            ->get();

        // Fix N+1: load all exchange rates for this company in one query
        // keyed by currency_id => collection of rates
        $allRates = ExchangeRate::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->orderByDesc('rate_date')
            ->get()
            ->groupBy('currency_id');

        return view('masters.currencies.index', compact('currencies', 'allRates'));
    }

    public function store(Request $request)
    {
        $this->gate('settings', 'edit');

        $companyId = auth()->user()->company_id;

        $validated = $request->validate([
            'code'           => ['required','string','size:3',
                Rule::unique('currencies')->where(fn($q) => $q->where('company_id', $companyId))],
            'name'           => 'required|string|max:50',
            'symbol'         => 'required|string|max:10',
            'decimal_places' => 'required|integer|min:0|max:4',
        ]);

        // Always uppercase currency code
        $validated['code'] = strtoupper($validated['code']);

        $currency = Currency::withoutGlobalScopes()->create(array_merge($validated, [
            'company_id' => $companyId,
            'is_base'    => false,
            'is_active'  => true,
        ]));

        AuditLog::record('create', 'currencies', (string) $currency->id, null,
            ['code' => $currency->code], "Currency added: {$currency->code}");

        return back()->with('success', "Currency '{$currency->code}' added successfully.");
    }

    public function update(Request $request, Currency $currency)
    {
        $this->gate('settings', 'edit');
        $this->sameCompany($currency);

        $validated = $request->validate([
            'name'           => 'required|string|max:50',
            'symbol'         => 'required|string|max:10',
            'decimal_places' => 'required|integer|min:0|max:4',
            'is_active'      => 'boolean',
        ]);

        $currency->update($validated);

        AuditLog::record('update', 'currencies', (string) $currency->id,
            null, $validated, "Currency updated: {$currency->code}");

        return back()->with('success', "Currency '{$currency->code}' updated.");
    }


    public function destroy(Currency $currency)
    {
        $this->gate('settings', 'edit');
        $this->sameCompany($currency);

        if ($currency->is_base) {
            return back()->withErrors(['error' => 'Cannot permanently delete the base currency. Deactivate other currencies instead.']);
        }

        $guard = app(\App\Services\MasterDeletionGuard::class);
        if ($message = $guard->blockingMessage($currency, $currency->code)) {
            return back()->withErrors(['error' => $message]);
        }

        $code = $currency->code;
        $id = $currency->id;
        $guard->hardDelete($currency);

        AuditLog::record('hard_delete', 'currencies', (string) $id,
            null, null, "Currency permanently deleted: {$code}");

        return back()->with('success', "Currency '{$code}' permanently deleted.");
    }

    public function updateRate(Request $request, Currency $currency)
    {
        $this->gate('settings', 'edit');
        $this->sameCompany($currency);

        if ($currency->is_base) {
            return back()->withErrors(['error' => 'Cannot set exchange rate for base currency.']);
        }

        $request->validate([
            'rate'      => 'required|numeric|min:0.000001',
            'rate_date' => 'required|date',
        ]);

        ExchangeRate::withoutGlobalScopes()->updateOrCreate(
            [
                'company_id'  => auth()->user()->company_id,
                'currency_id' => $currency->id,
                'rate_date'   => $request->rate_date,
            ],
            ['rate' => $request->rate]
        );

        return back()->with('success', "Exchange rate for {$currency->code} updated.");
    }

    private function sameCompany(Currency $currency): void
    {
        if ($currency->company_id !== auth()->user()->company_id) abort(403);
    }

    private function gate(string $module, string $action): void
    {
        if (!auth()->user()->hasPermission($module, $action)) abort(403);
    }
}
