<?php

namespace App\Http\Controllers\Company\Banking;

use App\Http\Controllers\Controller;
use App\Models\BankReconciliation;
use App\Services\BankReconciliationService;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\StreamedResponse;

class BankReconciliationController extends Controller
{
    public function __construct(
        private readonly BankReconciliationService $reconciliation,
    ) {
    }

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

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

    public function index(Request $request)
    {
        $this->gate('view');
        $companyId = $this->companyId();
        $accounts = $this->reconciliation->bankAccounts($companyId);
        $selectedAccountId = (int) $request->input('account_id', $accounts->first()?->id ?? 0);

        $workspace = null;
        if ($selectedAccountId > 0) {
            $inProgress = $this->reconciliation->inProgress($companyId, $selectedAccountId);
            if ($inProgress) {
                return redirect()->route('banking.reconciliation.show', $inProgress);
            }

            $workspace = [
                'account' => $accounts->firstWhere('id', $selectedAccountId),
                'beginning_balance' => $this->reconciliation->beginningBalance($companyId, $selectedAccountId),
                'history' => $this->reconciliation->history($companyId, $selectedAccountId),
            ];
        }

        return view('banking.reconciliation.index', [
            'accounts' => $accounts,
            'selectedAccountId' => $selectedAccountId,
            'workspace' => $workspace,
        ]);
    }

    public function show(Request $request, BankReconciliation $reconciliation)
    {
        $this->gate('view');
        $companyId = $this->companyId();
        $filters = $this->reconciliation->parseFilters($request, $reconciliation);
        $data = $this->reconciliation->workspace($companyId, $reconciliation, $filters);

        return view('banking.reconciliation.workspace', array_merge($data, [
            'accounts' => $this->reconciliation->bankAccounts($companyId),
            'companyId' => $companyId,
            'filters' => $filters,
            'filterOptions' => $this->reconciliation->filterOptions(
                $companyId,
                (int) $reconciliation->bankAccount()->value('account_id'),
                $reconciliation,
            ),
            'selectedPartyLabel' => $this->reconciliation->selectedPartyLabel($filters),
        ]));
    }

    public function start(Request $request, int $account)
    {
        $this->gate('reconcile');

        $validated = $request->validate([
            'statement_date' => 'required|date',
            'statement_balance' => 'required|numeric',
            'beginning_balance' => 'nullable|numeric',
            'notes' => 'nullable|string|max:5000',
        ]);

        $companyId = $this->companyId();
        $reco = $this->reconciliation->start($companyId, $account, $validated, auth()->id());

        return redirect()
            ->route('banking.reconciliation.show', $reco)
            ->with('success', 'Reconciliation started. Tick cleared transactions or upload a bank statement.');
    }

    public function save(Request $request, BankReconciliation $reconciliation)
    {
        $this->gate('reconcile');

        $validated = $request->validate([
            'statement_date' => 'required|date',
            'statement_balance' => 'required|numeric',
            'beginning_balance' => 'required|numeric',
            'notes' => 'nullable|string|max:5000',
            'cleared_entry_ids' => 'nullable|array',
            'cleared_entry_ids.*' => 'integer',
        ]);

        $companyId = $this->companyId();
        $this->reconciliation->saveProgress($companyId, $reconciliation, $validated);

        return back()->with('success', 'Reconciliation progress saved.');
    }

    public function finalize(Request $request, BankReconciliation $reconciliation)
    {
        $this->gate('reconcile');

        $validated = $request->validate([
            'statement_date' => 'required|date',
            'statement_balance' => 'required|numeric',
            'beginning_balance' => 'required|numeric',
            'notes' => 'nullable|string|max:5000',
            'cleared_entry_ids' => 'nullable|array',
            'cleared_entry_ids.*' => 'integer',
        ]);

        $companyId = $this->companyId();
        $reconciliation->load('bankAccount');
        $this->reconciliation->finalize($companyId, $reconciliation, $validated, auth()->id());

        return redirect()
            ->route('banking.reconciliation.index', ['account_id' => $reconciliation->bankAccount->account_id])
            ->with('success', 'Bank reconciliation completed.');
    }

    public function undo(BankReconciliation $reconciliation)
    {
        $this->gate('reconcile');
        $accountId = $reconciliation->bankAccount()->value('account_id');
        $this->reconciliation->undo($this->companyId(), $reconciliation);

        return redirect()
            ->route('banking.reconciliation.show', $reconciliation)
            ->with('success', 'Reconciliation reopened. You can edit and finish again.');
    }

    public function importStatement(Request $request, BankReconciliation $reconciliation)
    {
        $this->gate('reconcile');

        $validated = $request->validate([
            'statement_file' => 'required|file|mimes:csv,txt,xlsx,xls|max:5120',
        ]);

        $result = $this->reconciliation->importStatement(
            $this->companyId(),
            $reconciliation,
            $validated['statement_file'],
            auth()->id(),
        );

        return back()->with(
            'success',
            "Imported {$result['imported_rows']} statement line(s). Auto-matched {$result['auto_matched']} transaction(s).",
        );
    }

    public function autoMatch(BankReconciliation $reconciliation)
    {
        $this->gate('reconcile');
        $matched = $this->reconciliation->autoMatch($this->companyId(), $reconciliation);

        return back()->with('success', "Auto-matched {$matched} statement line(s).");
    }

    public function statementTemplate(): StreamedResponse
    {
        $this->gate('view');

        $headers = ['Date', 'Description', 'Reference', 'Debit', 'Credit', 'Balance'];
        $sample = ['2026-06-01', 'Customer payment', 'RCP-1001', '5000.00', '', '15000.00'];

        return response()->streamDownload(function () use ($headers, $sample) {
            $out = fopen('php://output', 'w');
            fputcsv($out, $headers);
            fputcsv($out, $sample);
            fclose($out);
        }, 'bank-statement-template.csv', [
            'Content-Type' => 'text/csv',
        ]);
    }
}
