<?php

namespace App\Http\Controllers\Company\Banking;

use App\Http\Controllers\Controller;
use App\Models\AuditLog;
use App\Models\ChequeFormat;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

class ChequeFormatsController extends Controller
{
    private function companyId(): int
    {
        return auth()->user()->company_id;
    }

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

    private function requireChequePrinting(): void
    {
        if (Setting::get($this->companyId(), 'use_cheque_printing', '0') !== '1') {
            abort(403, 'Enable Use Cheque Printing in Accounting Settings to access this feature.');
        }
    }

    private function sameCompany(ChequeFormat $chequeFormat): void
    {
        if ($chequeFormat->company_id !== $this->companyId()) {
            abort(403);
        }
    }

    public function index()
    {
        $this->gate('view');
        $this->requireChequePrinting();

        $formats = ChequeFormat::query()
            ->orderBy('name')
            ->get();

        return view('banking.cheque-formats.index', [
            'formats' => $formats,
            'sizePresets' => ChequeFormat::sizePresets(),
        ]);
    }

    public function store(Request $request)
    {
        $this->gate('view');
        $this->requireChequePrinting();

        $companyId = $this->companyId();

        $validated = $request->validate([
            'name' => [
                'required',
                'string',
                'max:100',
                Rule::unique('cheque_formats', 'name')->where(fn ($query) => $query->where('company_id', $companyId)),
            ],
            'page_width_mm' => 'required|numeric|min:50|max:400',
            'page_height_mm' => 'required|numeric|min:30|max:200',
        ]);

        $format = ChequeFormat::withoutGlobalScopes()->create([
            'company_id' => $companyId,
            'name' => $validated['name'],
            'page_width_mm' => $validated['page_width_mm'],
            'page_height_mm' => $validated['page_height_mm'],
            'layout' => ChequeFormat::defaultLayout(),
        ]);

        AuditLog::record('create', 'cheque_formats', (string) $format->id, null, [
            'name' => $format->name,
        ], "Cheque format created: {$format->name}");

        return redirect()
            ->route('banking.cheque-formats.design', $format)
            ->with('success', 'Cheque format created. Drag the fields into position, then save.');
    }

    public function design(ChequeFormat $chequeFormat)
    {
        $this->gate('view');
        $this->requireChequePrinting();
        $this->sameCompany($chequeFormat);

        return view('banking.cheque-formats.design', [
            'format' => $chequeFormat,
            'fieldMeta' => ChequeFormat::defaultLayout(),
            'sizePresets' => ChequeFormat::sizePresets(),
        ]);
    }

    public function update(Request $request, ChequeFormat $chequeFormat)
    {
        $this->gate('view');
        $this->requireChequePrinting();
        $this->sameCompany($chequeFormat);

        $companyId = $this->companyId();

        $validated = $request->validate([
            'name' => [
                'required',
                'string',
                'max:100',
                Rule::unique('cheque_formats', 'name')
                    ->where(fn ($query) => $query->where('company_id', $companyId))
                    ->ignore($chequeFormat->id),
            ],
            'page_width_mm' => 'required|numeric|min:50|max:400',
            'page_height_mm' => 'required|numeric|min:30|max:200',
            'layout' => 'required|array',
            'layout.payee' => 'required|array',
            'layout.date' => 'required|array',
            'layout.amount' => 'required|array',
            'layout.amount_words_1' => 'required|array',
            'layout.amount_words_2' => 'required|array',
            'layout.*.x' => 'required|numeric|min:0|max:400',
            'layout.*.y' => 'required|numeric|min:0|max:200',
            'layout.*.font_size' => 'required|numeric|min:6|max:24',
        ]);

        $layout = $this->mergeLayoutMeta($validated['layout']);

        $chequeFormat->update([
            'name' => $validated['name'],
            'page_width_mm' => $validated['page_width_mm'],
            'page_height_mm' => $validated['page_height_mm'],
            'layout' => $layout,
        ]);

        AuditLog::record('update', 'cheque_formats', (string) $chequeFormat->id, null, [
            'name' => $chequeFormat->name,
        ], "Cheque format updated: {$chequeFormat->name}");

        if ($request->expectsJson()) {
            return response()->json([
                'success' => true,
                'message' => 'Cheque format saved.',
            ]);
        }

        return back()->with('success', 'Cheque format saved.');
    }

    public function destroy(ChequeFormat $chequeFormat)
    {
        $this->gate('view');
        $this->requireChequePrinting();
        $this->sameCompany($chequeFormat);

        $name = $chequeFormat->name;
        $id = $chequeFormat->id;
        $chequeFormat->delete();

        AuditLog::record('delete', 'cheque_formats', (string) $id, null, null, "Cheque format deleted: {$name}");

        return redirect()
            ->route('banking.cheque-formats.index')
            ->with('success', "Cheque format '{$name}' deleted.");
    }

    private function mergeLayoutMeta(array $layout): array
    {
        $defaults = ChequeFormat::defaultLayout();
        $merged = [];

        foreach ($defaults as $key => $meta) {
            $field = $layout[$key] ?? [];
            $merged[$key] = [
                'label' => $meta['label'],
                'sample' => $meta['sample'],
                'x' => round((float) ($field['x'] ?? $meta['x']), 1),
                'y' => round((float) ($field['y'] ?? $meta['y']), 1),
                'font_size' => round((float) ($field['font_size'] ?? $meta['font_size']), 1),
            ];
        }

        return $merged;
    }
}
