<?php

namespace App\Http\Controllers;

use App\Models\ContractTemplate;
use App\Models\Loan;
use App\Models\LoanDocument;
use App\Services\AuditService;
use App\Services\ContractPreviewEditorService;
use App\Services\LoanApplicationService;
use App\Services\LoanContractPdfService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\ValidationException;

class LoanContractController extends Controller
{
    public function preview(Request $request, Loan $loan): RedirectResponse
    {
        $this->assertBranchAccess($request,$loan->branch_id);

        return redirect()->route('loans.show',$loan)->with(
            'info',
            'Contract layout corrections are managed in Administration → Contract Templates. Generate the completed contract directly from the loan.'
        );
    }

    public function previewPdf(Request $request, Loan $loan): RedirectResponse
    {
        $this->assertBranchAccess($request,$loan->branch_id);

        return redirect()->route('loans.show',$loan);
    }

    public function generate(
        Request $request,
        Loan $loan,
        LoanApplicationService $workflow,
        LoanContractPdfService $pdf,
        ContractPreviewEditorService $templates,
    ): Response|RedirectResponse {
        $this->assertBranchAccess($request,$loan->branch_id);
        abort_unless(
            $loan->canGenerateContract(),
            422,
            'A new contract cannot be generated while the application is under review or after it has been approved/rejected. A reviewer must first request correction, documents, or additional collateral.'
        );
        $this->assertStoredRequirements($loan);
        $loan->loadMissing(['branch.business','contractTemplate']);
        $template=$this->resolveTemplate($loan);

        if ($template) {
            // Template mapping, spacing and PDF placement are finalized in Administration.
            // Loan generation never accepts value or layout overrides.
            $content=$templates->generate($template,$loan);
            $extension=$template->isPdf()?'pdf':'docx';
            $mime=$template->isPdf()?'application/pdf':'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
            $filename=$loan->loan_number.'-contract.'.$extension;
            $path='loans/'.$loan->id.'/generated-contracts/'.now()->format('Ymd-His').'-'.$filename;
            Storage::disk('local')->put($path,$content);

            if ($loan->contract_template_id!==$template->id) {
                $loan->update(['contract_template_id'=>$template->id,'updated_by'=>$request->user()->id]);
            }

            $workflow->markContractGenerated($loan->fresh(),$request->user());
            $document=LoanDocument::create([
                'loan_id'=>$loan->id,
                'kind'=>'generated_contract',
                'document_type'=>'Generated Loan Contract',
                'original_name'=>$filename,
                'file_path'=>$path,
                'mime_type'=>$mime,
                'file_size'=>strlen($content),
                'notes'=>'Generated automatically from approved '.$extension.' contract template '.$template->name.' v'.$template->version.'.',
                'uploaded_by'=>$request->user()->id,
            ]);

            AuditService::record('loan_contract.generated',$document,[],[
                'loan_id'=>$loan->id,
                'contract_template_id'=>$template->id,
                'template_name'=>$template->name,
                'template_format'=>$extension,
                'contract_generated_at'=>$loan->fresh()->contract_generated_at,
                'generation_mode'=>'template_rules_only',
            ],$loan->branch_id);

            return response($content,200,[
                'Content-Type'=>$mime,
                'Content-Disposition'=>'attachment; filename="'.$filename.'"',
                'Content-Length'=>(string)strlen($content),
                'Cache-Control'=>'private, no-store, max-age=0',
            ]);
        }

        $content=$pdf->generate($loan->fresh(),$loan->branch->business);
        $workflow->markContractGenerated($loan,$request->user());
        AuditService::record('loan_contract.generated',$loan,[],[
            'contract_generated_at'=>$loan->fresh()->contract_generated_at,
            'fallback'=>'generic_pdf',
        ],$loan->branch_id);

        return response($content,200,[
            'Content-Type'=>'application/pdf',
            'Content-Disposition'=>'attachment; filename="'.$loan->loan_number.'-contract.pdf"',
            'Content-Length'=>(string)strlen($content),
        ]);
    }

    private function resolveTemplate(Loan $loan): ?ContractTemplate
    {
        $loan->loadMissing(['branch.business','contractTemplate']);
        if ($loan->contractTemplate) return $loan->contractTemplate;

        return ContractTemplate::query()
            ->where('business_id',$loan->branch->business_id)
            ->where('status','active')
            ->where('is_default',true)
            ->first();
    }

    private function assertStoredRequirements(Loan $loan): void
    {
        $loan->loadMissing(['product','collaterals','guarantor']);
        if ($loan->product->collateral_required && $loan->collaterals->isEmpty()) {
            throw ValidationException::withMessages(['collateral'=>'Required collateral is missing.']);
        }
        if ($loan->product->guarantor_required && ! $loan->guarantor) {
            throw ValidationException::withMessages(['guarantor'=>'Required guarantor is missing.']);
        }
    }

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