<?php

namespace App\Http\Controllers\Company\Banking;

use App\Http\Controllers\Controller;
use App\Models\AuditLog;
use App\Models\ChequeFormat;
use App\Models\ChequePrintQueueItem;
use App\Models\Setting;
use App\Models\Voucher;
use App\Services\ChequePrintService;
use Illuminate\Http\Request;

class ChequePrintController extends Controller
{
    public function __construct(
        private readonly ChequePrintService $chequePrint,
    ) {
    }

    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.');
        }
    }

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

        $companyId = $this->companyId();

        return view('banking.cheque-print.index', [
            'formats' => ChequeFormat::query()->orderBy('name')->get(['id', 'name']),
            'queueItems' => $this->chequePrint->eligibleVouchers($companyId),
        ]);
    }

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

        $validated = $request->validate([
            'voucher_ids' => 'required|array|min:1',
            'voucher_ids.*' => 'integer',
        ]);

        $added = $this->chequePrint->addToQueue(
            $this->companyId(),
            $validated['voucher_ids'],
            auth()->id(),
        );

        return back()->with(
            'success',
            $added > 0
                ? $added . ' voucher' . ($added === 1 ? '' : 's') . ' added to the cheque print queue.'
                : 'Selected vouchers are already in the queue or are not eligible.',
        );
    }

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

        $validated = $request->validate([
            'voucher_ids' => 'required|array|min:1',
            'voucher_ids.*' => 'integer',
        ]);

        $removed = $this->chequePrint->removeFromQueue($this->companyId(), $validated['voucher_ids']);

        return back()->with(
            'success',
            $removed > 0
                ? $removed . ' voucher' . ($removed === 1 ? '' : 's') . ' removed from the queue.'
                : 'No vouchers were removed.',
        );
    }

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

        $companyId = $this->companyId();

        $validated = $request->validate([
            'cheque_format_id' => 'required|integer|exists:cheque_formats,id',
            'voucher_ids' => 'required|array|min:1',
            'voucher_ids.*' => 'integer',
        ]);

        $format = ChequeFormat::query()->findOrFail($validated['cheque_format_id']);
        if ($format->company_id !== $companyId) {
            abort(403);
        }

        $eligibleIds = $this->chequePrint->eligibleVoucherIds($companyId, $validated['voucher_ids']);

        if ($eligibleIds === []) {
            return back()->withErrors(['error' => 'Select posted Bank Payment or eligible Contra vouchers with a cheque number that have not been printed yet.']);
        }

        $vouchers = Voucher::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->whereIn('id', $eligibleIds)
            ->with(['lines.account:id,code,name,is_bank,is_cash'])
            ->get();

        $cheques = $vouchers->map(function (Voucher $voucher) use ($companyId) {
            $presented = $this->chequePrint->presentVoucher($voucher, $companyId, true);
            [$words1, $words2] = $this->chequePrint->splitAmountWords($presented['amount_words']);

            return array_merge($presented, [
                'amount_words_1' => $words1,
                'amount_words_2' => $words2,
                'voucher' => $voucher,
            ]);
        });

        foreach ($vouchers as $voucher) {
            $this->chequePrint->markPrinted($voucher);
        }

        ChequePrintQueueItem::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->whereIn('voucher_id', $eligibleIds)
            ->delete();

        AuditLog::record('print', 'cheque_print', null, null, [
            'format' => $format->name,
            'voucher_ids' => $eligibleIds,
        ], 'Cheques printed: ' . count($eligibleIds));

        return view('banking.cheque-print.print', [
            'format' => $format,
            'cheques' => $cheques,
            'closeUrl' => route('banking.cheque-print.index'),
        ]);
    }
}
