<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Branch;
use App\Models\Business;
use App\Models\LoanProduct;
use App\Models\User;
use App\Services\AuditService;
use App\Services\BranchAccessService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Illuminate\View\View;

class BranchController extends Controller
{
    public function index(Request $request, BranchAccessService $branchAccess): View
    {
        $query = Branch::with(['business', 'manager'])->orderBy('name');
        if (! $branchAccess->isSystemWide($request->user())) {
            $query->whereIn('id', $request->user()->branches()->select('branches.id'));
        }

        if ($request->filled('search')) {
            $search = trim((string) $request->string('search'));
            $query->where(function ($builder) use ($search): void {
                $builder->where('name', 'like', "%{$search}%")
                    ->orWhere('code', 'like', "%{$search}%")
                    ->orWhere('location', 'like', "%{$search}%")
                    ->orWhere('region', 'like', "%{$search}%")
                    ->orWhere('district', 'like', "%{$search}%");
            });
        }

        if ($request->filled('status')) {
            $query->where('status', $request->string('status'));
        }

        return view('admin.branches.index', ['branches' => $query->paginate(20)->withQueryString()]);
    }

    public function create(): View
    {
        return view('admin.branches.form', [
            'branch' => new Branch(),
            'businesses' => Business::orderBy('name')->get(),
            'managers' => User::where('status', 'active')->orderBy('name')->get(),
            'loanProducts' => LoanProduct::orderBy('business_id')->orderBy('name')->get(),
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $data = $this->validated($request);
        $loanProductIds = array_map('intval', $data['loan_product_ids'] ?? []);
        unset($data['loan_product_ids']);

        $branch = DB::transaction(function () use ($data, $loanProductIds): Branch {
            $branch = Branch::create($data);
            $branch->loanProducts()->sync($loanProductIds);

            return $branch;
        });

        $after = $branch->fresh()->load('loanProducts:id')->toArray();
        AuditService::record('branch.created', $branch, [], $after, $branch->id);

        return redirect()->route('admin.branches.index')->with('success', 'Branch created.');
    }

    public function edit(Request $request, Branch $branch): View
    {
        abort_unless($request->user()->canAccessBranch($branch->id), 403);
        $branch->load('loanProducts');

        return view('admin.branches.form', [
            'branch' => $branch,
            'businesses' => Business::orderBy('name')->get(),
            'managers' => User::where('status', 'active')->orderBy('name')->get(),
            'loanProducts' => LoanProduct::orderBy('business_id')->orderBy('name')->get(),
        ]);
    }

    public function update(Request $request, Branch $branch): RedirectResponse
    {
        abort_unless($request->user()->canAccessBranch($branch->id), 403);
        $branch->load('loanProducts:id');
        $before = $branch->toArray();

        $data = $this->validated($request, $branch);
        $loanProductIds = array_map('intval', $data['loan_product_ids'] ?? []);
        unset($data['loan_product_ids']);

        DB::transaction(function () use ($branch, $data, $loanProductIds): void {
            $branch->update($data);
            $branch->loanProducts()->sync($loanProductIds);
        });

        $after = $branch->fresh()->load('loanProducts:id')->toArray();
        AuditService::record('branch.updated', $branch, $before, $after, $branch->id);

        return redirect()->route('admin.branches.index')->with('success', 'Branch updated.');
    }

    private function validated(Request $request, ?Branch $branch = null): array
    {
        return $request->validate([
            'business_id' => ['required', 'exists:businesses,id'],
            'name' => ['required', 'string', 'max:255'],
            'location' => ['nullable', 'string', 'max:255'],
            'address' => ['nullable', 'string', 'max:255'],
            'region' => ['nullable', 'string', 'max:255'],
            'district' => ['nullable', 'string', 'max:255'],
            'phone' => ['nullable', 'string', 'max:50'],
            'email' => ['nullable', 'email', 'max:255'],
            'manager_user_id' => ['nullable', 'exists:users,id'],
            'opening_date' => ['nullable', 'date'],
            'status' => ['required', Rule::in(['active', 'inactive'])],
            'loan_product_ids' => ['nullable', 'array'],
            'loan_product_ids.*' => [
                'integer',
                'distinct',
                Rule::exists('loan_products', 'id')->where(
                    fn ($query) => $query->where('business_id', $request->integer('business_id')),
                ),
            ],
        ]);
    }
}
