<?php

namespace App\Http\Controllers;

use App\Models\Business;
use App\Models\Collateral;
use App\Models\Expense;
use App\Models\Loan;
use App\Models\LoanDisbursement;
use App\Models\LoanPayment;
use App\Services\BrandedPdfService;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;

class DocumentExportController extends Controller
{
    public function branding(Request $request, Business $business, string $asset): Response
    {
        abort_unless(in_array($asset, ['logo','stamp'], true), 404);
        $this->assertBusinessAccess($request, $business);
        $path = $asset === 'logo' ? $business->logo_path : $business->stamp_path;
        abort_unless($path && Storage::disk('local')->exists($path), 404);
        $mime = Storage::disk('local')->mimeType($path) ?: 'application/octet-stream';
        return response(Storage::disk('local')->get($path), 200, [
            'Content-Type' => $mime,
            'Content-Disposition' => 'inline; filename="'.basename($path).'"',
            'Cache-Control' => 'private, max-age=300',
            'X-Content-Type-Options' => 'nosniff',
        ]);
    }

    public function loanAgreementPrint(Request $request, Loan $loan): View
    {
        $this->assertBranchAccess($request, $loan->branch_id);
        abort_unless($loan->contract_generated_at, 422, 'Generate the loan agreement before printing it.');
        $loan->load(['customer','branch.business','product','guarantor','collaterals.category','installments']);
        return view('documents.loan-agreement', compact('loan'));
    }

    public function paymentReceiptPdf(Request $request, LoanPayment $payment, BrandedPdfService $pdf): Response
    {
        $this->assertBranchAccess($request, $payment->branch_id);
        $payment->load(['loan.product','customer','branch.business','financialAccount','receiver']);
        $business = $payment->branch->business;
        $lines = [
            'Branch: '.$payment->branch->name,
            'Date: '.$payment->payment_date->format('d M Y H:i'),
            'Customer: '.$payment->customer->full_name.' ('.$payment->customer->customer_number.')',
            'Phone: '.$payment->customer->phone,
            'Loan: '.$payment->loan->loan_number.' — '.$payment->loan->product->name,
            'Method: '.str($payment->method)->replace('_',' ')->headline(),
            'Account: '.$payment->financialAccount->name,
            'Payment Reference: '.($payment->reference ?: 'N/A'),
            '',
            'AMOUNT RECEIVED: '.$pdf->money($business, $payment->amount),
            'Principal: '.$pdf->money($business, $payment->principal_amount),
            'Interest: '.$pdf->money($business, $payment->interest_amount),
            'Fees: '.$pdf->money($business, $payment->fees_amount),
            'Penalties: '.$pdf->money($business, $payment->penalties_amount),
            'Remaining Loan Balance: '.$pdf->money($business, $payment->loan->total_outstanding),
            '',
            'Received By: '.($payment->receiver?->name ?: 'System'),
            'Notes: '.($payment->notes ?: 'None'),
            '',
            'Customer Signature: __________________________',
            'Authorized Staff: ____________________________',
        ];
        return $this->pdfResponse($pdf->generate($business, 'LOAN PAYMENT RECEIPT', $lines, $payment->receipt_number), $payment->receipt_number.'.pdf');
    }

    public function loanStatementPdf(Request $request, Loan $loan, BrandedPdfService $pdf): Response
    {
        $this->assertBranchAccess($request, $loan->branch_id);
        $loan->load(['customer','branch.business','product','statementEntries','installments','payments.receiver']);
        $business = $loan->branch->business;
        $lines = [
            'Branch: '.$loan->branch->name,
            'Customer: '.$loan->customer->full_name.' ('.$loan->customer->customer_number.')',
            'Phone: '.$loan->customer->phone,
            'Product: '.$loan->product->name,
            'Status: '.str($loan->status)->replace('_',' ')->headline(),
            'Original Total: '.$pdf->money($business, $loan->total_repayment),
            'Paid: '.$pdf->money($business, $loan->total_paid),
            'Outstanding: '.$pdf->money($business, $loan->total_outstanding),
            '',
            'STATEMENT ENTRIES',
            'Date         Reference             Debit          Credit         Balance',
        ];
        foreach ($loan->statementEntries as $entry) {
            $lines[] = sprintf('%-12s %-20s %12s %12s %12s', $entry->entry_date->format('Y-m-d'), mb_substr((string)$entry->reference,0,20), $entry->debit, $entry->credit, $entry->running_balance);
            if ($entry->description) $lines[] = '  '.mb_substr($entry->description,0,88);
        }
        $lines[] = '';
        $lines[] = 'REPAYMENT SCHEDULE';
        $lines[] = '#   Due Date     Principal Paid  Interest Paid  Fees Paid   Penalty Paid  Remaining';
        foreach ($loan->installments as $entry) {
            $lines[] = sprintf('%-3s %-12s %14s %14s %10s %12s %12s', $entry->installment_number, $entry->due_date->format('Y-m-d'), $entry->principal_paid, $entry->interest_paid, $entry->fees_paid, $entry->penalty_paid, $entry->remaining);
        }
        return $this->pdfResponse($pdf->generate($business, 'LOAN STATEMENT', $lines, $loan->loan_number), $loan->loan_number.'-statement.pdf');
    }

    public function collateralReceiptPdf(Request $request, Collateral $collateral, BrandedPdfService $pdf): Response
    {
        $this->assertBranchAccess($request, $collateral->branch_id);
        $collateral->load(['customer','branch.business','category','receiver']);
        return $this->collateralPdf($collateral, null, 'COLLATERAL RECEIPT', $pdf);
    }

    public function collateralReleasePdf(Request $request, Collateral $collateral, BrandedPdfService $pdf): Response
    {
        $this->assertBranchAccess($request, $collateral->branch_id);
        $movement = $collateral->movements()->whereIn('to_status',['released','returned'])->with('mover')->latest('moved_at')->first();
        abort_unless($movement, 404, 'No release/return movement has been recorded for this collateral.');
        $collateral->load(['customer','branch.business','category','receiver']);
        return $this->collateralPdf($collateral, $movement, 'COLLATERAL RELEASE ACKNOWLEDGEMENT', $pdf);
    }

    public function disbursementReceiptPdf(Request $request, LoanDisbursement $disbursement, BrandedPdfService $pdf): Response
    {
        $this->assertBranchAccess($request, $disbursement->branch_id);
        $disbursement->load(['loan.customer','loan.product','branch.business','financialAccount','user','accountTransaction']);
        $business = $disbursement->branch->business;
        $lines = [
            'Branch: '.$disbursement->branch->name,
            'Date: '.$disbursement->disbursement_date->format('d M Y'),
            'Customer: '.$disbursement->loan->customer->full_name.' ('.$disbursement->loan->customer->customer_number.')',
            'Phone: '.$disbursement->loan->customer->phone,
            'Loan: '.$disbursement->loan->loan_number.' — '.$disbursement->loan->product->name,
            'Financial Account: '.$disbursement->financialAccount->name,
            'Reference: '.($disbursement->reference ?: 'N/A'),
            'Account Transaction: '.($disbursement->accountTransaction?->transaction_number ?: 'N/A'),
            '',
            'AMOUNT DISBURSED: '.$pdf->money($business, $disbursement->amount),
            '',
            'Disbursed By: '.($disbursement->user?->name ?: 'System'),
            'Notes: '.($disbursement->notes ?: 'None'),
            '',
            'Customer Signature / Acknowledgement: __________________________',
            'Authorized Staff Signature: ___________________________________',
        ];
        return $this->pdfResponse($pdf->generate($business, 'LOAN DISBURSEMENT RECEIPT', $lines, $disbursement->disbursement_number), $disbursement->disbursement_number.'.pdf');
    }

    public function expenseVoucherPrint(Request $request, Expense $expense): View
    {
        $this->assertExpenseVoucher($request, $expense);
        $expense->load(['branch.business','category','financialAccount','enteredBy','approver','accountTransaction']);
        return view('documents.expense-voucher', compact('expense'));
    }

    public function expenseVoucherPdf(Request $request, Expense $expense, BrandedPdfService $pdf): Response
    {
        $this->assertExpenseVoucher($request, $expense);
        $expense->load(['branch.business','category','financialAccount','enteredBy','approver','accountTransaction']);
        $business = $expense->branch->business;
        $lines = [
            'Branch: '.$expense->branch->name,
            'Expense Date: '.$expense->expense_date->format('d M Y'),
            'Category: '.$expense->category->name,
            'Description: '.$expense->description,
            'Supplier / Payee: '.($expense->supplier ?: 'N/A'),
            'Financial Account: '.$expense->financialAccount->name,
            'Account Transaction: '.($expense->accountTransaction?->transaction_number ?: 'N/A'),
            'Accounting Journal: '.($expense->accounting_journal_number ?: 'N/A'),
            '',
            'AMOUNT: '.$pdf->money($business, $expense->amount),
            '',
            'Entered By: '.($expense->enteredBy?->name ?: 'N/A'),
            'Approved By: '.($expense->approver?->name ?: 'N/A'),
            'Approved At: '.($expense->approved_at?->format('d M Y H:i') ?: 'N/A'),
            'Approval Comments: '.($expense->decision_comments ?: 'None'),
            'Notes: '.($expense->notes ?: 'None'),
            '',
            'Prepared By: _________________________',
            'Approved By: _________________________',
            'Payee Signature: _____________________',
        ];
        return $this->pdfResponse($pdf->generate($business, 'EXPENSE VOUCHER', $lines, $expense->expense_number), $expense->expense_number.'-voucher.pdf');
    }

    private function collateralPdf(Collateral $collateral, $movement, string $title, BrandedPdfService $pdf): Response
    {
        $business = $collateral->branch->business;
        $lines = [
            'Branch: '.$collateral->branch->name,
            'Customer: '.$collateral->customer->full_name.' ('.$collateral->customer->customer_number.')',
            'Phone: '.$collateral->customer->phone,
            'Category / Item: '.$collateral->category->name.' — '.$collateral->item,
            'Brand / Model / Serial: '.(collect([$collateral->brand,$collateral->model,$collateral->serial_number])->filter()->join(' / ') ?: 'N/A'),
            'Condition: '.($collateral->condition ?: 'N/A'),
            'Accepted Value: '.$pdf->money($business, $collateral->accepted_value),
            'Received: '.($collateral->received_at?->format('d M Y') ?: 'N/A'),
            'Received By: '.($collateral->receiver?->name ?: 'N/A'),
            'Status: '.str($collateral->status)->replace('_',' ')->headline(),
            'Storage Location: '.($collateral->storage_location ?: 'N/A'),
        ];
        if ($movement) {
            $lines[] = '';
            $lines[] = 'Release / Return Date: '.$movement->moved_at->format('d M Y H:i');
            $lines[] = 'Released / Returned By: '.($movement->mover?->name ?: 'N/A');
            $lines[] = 'Release Note: '.($movement->notes ?: 'None');
        }
        $lines[] = '';
        $lines[] = 'Customer / Recipient Signature: __________________________';
        $lines[] = 'Authorized Staff Signature: ______________________________';
        $suffix = $movement ? '-release-acknowledgement.pdf' : '-receipt.pdf';
        return $this->pdfResponse($pdf->generate($business, $title, $lines, $collateral->code), $collateral->code.$suffix);
    }

    private function assertExpenseVoucher(Request $request, Expense $expense): void
    {
        $this->assertBranchAccess($request, $expense->branch_id);
        abort_unless($expense->status === 'approved' && $expense->financial_account_transaction_id && $expense->accounting_journal_number, 422, 'Expense voucher is available only after approval and financial posting.');
    }

    private function assertBusinessAccess(Request $request, Business $business): void
    {
        $branchIds = app(\App\Services\BranchAccessService::class)->accessibleBranchIds($request->user());
        abort_unless($business->branches()->whereIn('id', $branchIds)->exists(), 403);
    }

    private function assertBranchAccess(Request $request, int $branchId): void
    {
        abort_unless($request->user()->canAccessBranch($branchId), 403);
    }

    private function pdfResponse(string $content, string $filename): Response
    {
        return response($content, 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => 'attachment; filename="'.$filename.'"',
            'Content-Length' => (string) strlen($content),
            'X-Content-Type-Options' => 'nosniff',
        ]);
    }
}
