<?php

namespace App\Http\Controllers\Api\ExtraCharges;

use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\ExtraCharges\StoreExtraChargeRequest;
use App\Http\Requests\ExtraCharges\UpdateExtraChargeRequest;
use App\Http\Resources\ExtraCharges\ExtraChargeInvoiceOptionResource;
use App\Http\Resources\ExtraCharges\ExtraChargeParentOptionResource;
use App\Http\Resources\ExtraCharges\ExtraChargeResource;
use App\Models\AdditionalCharge;
use App\Services\ExtraCharges\ExtraChargesChargeService;
use App\Services\ExtraCharges\ExtraChargesContextService;
use App\Services\ExtraCharges\ExtraChargesInvoiceService;
use App\Services\ExtraCharges\ExtraChargesListService;
use App\Services\ExtraCharges\ExtraChargesMetaService;
use App\Services\ExtraCharges\ExtraChargesParentService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class ExtraChargesController extends BaseApiController
{
    public function __construct(
        private ExtraChargesContextService $context,
        private ExtraChargesMetaService $meta,
        private ExtraChargesParentService $parents,
        private ExtraChargesInvoiceService $invoices,
        private ExtraChargesListService $listService,
        private ExtraChargesChargeService $chargeService
    ) {
        parent::__construct();
    }

    public function list(Request $request): JsonResponse
    {
        $year = (string) ($request->query('school_year') ?? $this->context->getSchoolYear());
        $sem = (string) ($request->query('semester') ?? $this->context->getSemester());
        $status = $request->query('status') ?: null;
        $q = trim((string) ($request->query('q') ?? '')) ?: null;
        $per = (int) ($request->query('per_page') ?? 50);

        [$rows, $meta] = $this->listService->listForTerm($year, $sem, $status, $q, $per);

        return response()->json([
            'ok' => true,
            'school_year' => $year,
            'semester' => $sem,
            'rows' => ExtraChargeResource::collection($rows),
            'pager' => $meta,
        ]);
    }

    public function options(Request $request): JsonResponse
    {
        $q = trim((string) ($request->query('q') ?? ''));
        $parentOptions = $this->parents->searchParents($q);

        return response()->json([
            'ok' => true,
            'schoolYear' => $this->context->getSchoolYear(),
            'semester' => $this->context->getSemester(),
            'schoolYears' => $this->meta->getSchoolYears($this->context->getSchoolYear()),
            'parents' => ExtraChargeParentOptionResource::collection($parentOptions),
        ]);
    }

    public function parentOptions(Request $request): JsonResponse
    {
        $q = trim((string) ($request->query('q') ?? ''));
        $parentOptions = $this->parents->searchParents($q);

        return response()->json([
            'results' => ExtraChargeParentOptionResource::collection($parentOptions),
        ]);
    }

    public function invoicesForParent(Request $request): JsonResponse
    {
        $parentId = (int) ($request->query('parent_id') ?? 0);
        $schoolYear = (string) ($request->query('school_year') ?? $this->context->getSchoolYear());
        $rows = $this->invoices->listInvoicesForParent($parentId, $schoolYear);

        return response()->json([
            'results' => ExtraChargeInvoiceOptionResource::collection($rows),
        ]);
    }

    public function store(StoreExtraChargeRequest $request): JsonResponse
    {
        $payload = $request->validated();
        $payload['created_by'] = (int) (auth()->id() ?? 0);

        $result = $this->chargeService->createCharge($payload);

        return response()->json($result, $result['ok'] ? 201 : 422);
    }

    public function update(UpdateExtraChargeRequest $request, int $id): JsonResponse
    {
        $charge = AdditionalCharge::query()->find($id);
        if (!$charge) {
            return response()->json(['ok' => false, 'error' => 'Charge not found'], 404);
        }

        $payload = $request->validated();
        $payload['updated_by'] = (int) (auth()->id() ?? 0);

        $ok = $this->chargeService->updateCharge($charge, $payload);

        return response()->json([
            'ok' => $ok,
            'id' => $id,
        ], $ok ? 200 : 422);
    }

    public function void(int $id): JsonResponse
    {
        $charge = AdditionalCharge::query()->find($id);
        if (!$charge) {
            return response()->json(['ok' => false, 'error' => 'Charge not found'], 404);
        }

        $ok = $this->chargeService->voidCharge($charge);

        return response()->json([
            'ok' => $ok,
        ], $ok ? 200 : 422);
    }

    public function reverse(int $id): JsonResponse
    {
        $charge = AdditionalCharge::query()->find($id);
        if (!$charge) {
            return response()->json(['ok' => false, 'error' => 'Charge not found'], 404);
        }

        $ok = $this->chargeService->reverseCharge($charge);

        return response()->json([
            'ok' => $ok,
        ], $ok ? 200 : 422);
    }
}
