<?php

namespace App\Http\Controllers;

use App\Models\Branch;
use App\Models\FinancialAccount;
use App\Services\AuditService;
use App\Services\FinancialAccountingService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\View\View;

class FinancialAccountController extends Controller
{
    public function index(Request $request): View
    {
        $query = FinancialAccount::with('branch')->whereIn('branch_id',$this->allowedBranchIds($request))->latest('id');
        if ($request->filled('search')) {
            $search=trim((string)$request->string('search'));
            $query->where(fn($q)=>$q->where('name','like',"%{$search}%")->orWhere('reference_details','like',"%{$search}%"));
        }
        if ($request->filled('type')) $query->where('account_type',$request->string('type'));
        if ($request->filled('status')) $query->where('status',$request->string('status'));
        if ($request->filled('branch')) $query->where('branch_id',$request->integer('branch'));

        return view('accounts.index',[
            'accounts'=>$query->paginate(20)->withQueryString(),
            'branches'=>Branch::whereIn('id',$this->allowedBranchIds($request))->orderBy('name')->get(),
            'types'=>FinancialAccount::TYPES,
        ]);
    }

    public function create(Request $request): View
    {
        return view('accounts.form',['account'=>new FinancialAccount(['status'=>'active','opening_balance'=>'0.00']),'branches'=>$this->branches($request)]);
    }

    public function store(Request $request, FinancialAccountingService $service): RedirectResponse
    {
        $data=$this->validated($request);
        $this->assertBranchAccess($request,(int)$data['branch_id']);
        $account=$service->createAccount($data,$request->user());
        AuditService::record('financial_account.created',$account,[],$account->toArray(),$account->branch_id);
        return redirect()->route('accounts.show',$account)->with('success','Financial account created.');
    }

    public function show(Request $request, FinancialAccount $account): View
    {
        $this->assertBranchAccess($request,$account->branch_id);
        $transactions=$account->transactions()->with(['user','branch','transfer','related'])->paginate(30)->withQueryString();
        return view('accounts.show',['account'=>$account->load('branch'),'transactions'=>$transactions]);
    }

    public function edit(Request $request, FinancialAccount $account): View
    {
        $this->assertBranchAccess($request,$account->branch_id);
        return view('accounts.form',['account'=>$account,'branches'=>$this->branches($request)]);
    }

    public function update(Request $request, FinancialAccount $account): RedirectResponse
    {
        $this->assertBranchAccess($request,$account->branch_id);
        $data=$request->validate([
            'name'=>['required','string','max:150'],
            'account_type'=>['required',Rule::in(FinancialAccount::TYPES)],
            'status'=>['required',Rule::in(FinancialAccount::STATUSES)],
            'reference_details'=>['nullable','string','max:3000'],
        ]);
        $before=$account->toArray();
        $account->update(array_merge($data,['updated_by'=>$request->user()->id]));
        AuditService::record('financial_account.updated',$account,$before,$account->fresh()->toArray(),$account->branch_id);
        return redirect()->route('accounts.show',$account)->with('success','Financial account updated.');
    }

    private function validated(Request $request): array
    {
        return $request->validate([
            'branch_id'=>['required','integer','exists:branches,id'],
            'name'=>['required','string','max:150'],
            'account_type'=>['required',Rule::in(FinancialAccount::TYPES)],
            'opening_balance'=>['required','decimal:0,2','min:0'],
            'status'=>['required',Rule::in(FinancialAccount::STATUSES)],
            'reference_details'=>['nullable','string','max:3000'],
        ]);
    }

    private function branches(Request $request)
    {
        return Branch::whereIn('id',$this->allowedBranchIds($request))->where('status','active')->orderBy('name')->get();
    }

    private function allowedBranchIds(Request $request)
    {
        return collect(app(\App\Services\BranchAccessService::class)->accessibleBranchIds($request->user()));
    }

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