<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\V1;

use App\Enums\TransferStatus;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreTransferRequest;
use App\Http\Resources\TransferResource;
use App\Models\Member;
use App\Models\MemberTransfer;
use App\Services\BranchAccessService;
use App\Services\TransferService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class TransferController extends Controller
{
    public function __construct(
        private readonly BranchAccessService $branchAccess,
        private readonly TransferService $transfers,
    ) {}

    public function index(Request $request): JsonResponse
    {
        $query = MemberTransfer::visibleTo($request->user())
            ->with(['member:id,first_name,last_name,member_number', 'fromBranch:id,name,code', 'toBranch:id,name,code', 'requestedBy:id,name', 'decidedBy:id,name'])
            ->orderByDesc('created_at');

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

        $branchIds = $this->branchAccess->accessibleBranchIds($request->user());

        if ($request->query('direction') === 'inbound' && $branchIds !== null) {
            $query->whereIn('to_branch_id', $branchIds);
        } elseif ($request->query('direction') === 'outbound' && $branchIds !== null) {
            $query->whereIn('from_branch_id', $branchIds);
        }

        $perPage = (int) ($request->integer('per_page') ?: 25);
        $transfers = $query->cursorPaginate($perPage)->withQueryString();

        return TransferResource::collection($transfers)->response();
    }

    public function store(StoreTransferRequest $request): JsonResponse
    {
        $member = Member::visibleTo($request->user())->findOrFail($request->input('member_id'));

        $transfer = MemberTransfer::create([
            'member_id' => $member->id,
            'from_branch_id' => $member->branch_id,
            'to_branch_id' => $request->input('to_branch_id'),
            'status' => TransferStatus::Pending,
            'reason' => $request->input('reason'),
            'requested_by' => $request->user()->id,
        ]);

        return (new TransferResource($transfer->load(['member', 'fromBranch', 'toBranch', 'requestedBy'])))
            ->response()
            ->setStatusCode(201);
    }

    public function approve(Request $request, MemberTransfer $transfer): TransferResource
    {
        $this->authorize('approve', $transfer);

        if ($transfer->status !== TransferStatus::Pending) {
            abort(409, 'This transfer has already been decided.');
        }

        $transfer = $this->transfers->approve($transfer, $request->user());

        return new TransferResource($transfer);
    }

    public function reject(Request $request, MemberTransfer $transfer): TransferResource
    {
        $this->authorize('reject', $transfer);

        if ($transfer->status !== TransferStatus::Pending) {
            abort(409, 'This transfer has already been decided.');
        }

        $transfer->update([
            'status' => TransferStatus::Rejected,
            'decided_by' => $request->user()->id,
            'decided_at' => now(),
        ]);

        return new TransferResource($transfer->fresh(['member', 'fromBranch', 'toBranch', 'requestedBy', 'decidedBy']));
    }

    public function cancel(Request $request, MemberTransfer $transfer): TransferResource
    {
        $this->authorize('cancel', $transfer);

        if ($transfer->status !== TransferStatus::Pending) {
            abort(409, 'This transfer has already been decided.');
        }

        $transfer->update([
            'status' => TransferStatus::Cancelled,
            'decided_by' => $request->user()->id,
            'decided_at' => now(),
        ]);

        return new TransferResource($transfer->fresh(['member', 'fromBranch', 'toBranch', 'requestedBy', 'decidedBy']));
    }
}
