<?php

namespace App\Http\Controllers\Api\Finance;

use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Invoices\InvoiceManagementRequest;
use App\Http\Requests\Invoices\InvoiceParentRequest;
use App\Http\Requests\Invoices\InvoiceStatusRequest;
use App\Http\Resources\Invoices\InvoiceManagementParentResource;
use App\Http\Resources\Invoices\InvoiceResource;
use App\Models\Invoice;
use App\Services\Invoices\InvoiceGenerationService;
use App\Services\Invoices\InvoiceManagementService;
use App\Services\Invoices\InvoicePaymentService;
use App\Services\Invoices\InvoicePdfService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Symfony\Component\HttpFoundation\StreamedResponse;

class InvoiceController extends BaseApiController
{
    public function __construct(
        private InvoiceManagementService $management,
        private InvoiceGenerationService $generation,
        private InvoicePaymentService $paymentService,
        private InvoicePdfService $pdfService
    ) {
        parent::__construct();
    }

    public function management(InvoiceManagementRequest $request): JsonResponse
    {
        $schoolYear = $request->validated()['school_year'] ?? null;
        $schoolYear = $schoolYear ?: $request->input('schoolYear');
        $schoolYear = $schoolYear ?: $request->input('year');

        $data = $this->management->getManagementData($schoolYear);

        return response()->json([
            'ok' => true,
            'schoolYear' => $data['schoolYear'],
            'schoolYears' => $data['schoolYears'],
            'invoices' => InvoiceManagementParentResource::collection($data['invoices']),
        ]);
    }

    public function generate(Request $request): JsonResponse
    {
        $data = array_merge($request->query->all(), $request->all(), $request->json()->all());
        $validator = Validator::make($data, [
            'parent_id' => ['required', 'integer', 'exists:users,id'],
            'school_year' => ['nullable', 'string', 'max:20'],
        ]);

        if ($validator->fails()) {
            return response()->json([
                'message' => 'Validation failed.',
                'errors' => $validator->errors(),
            ], 422);
        }

        $payload = $validator->validated();
        $result = $this->generation->generateInvoice((int) $payload['parent_id'], $payload['school_year'] ?? null);

        if (empty($result['ok'])) {
            return response()->json(['ok' => false, 'message' => $result['message'] ?? 'Unable to generate invoice.'], 422);
        }

        return response()->json([
            'ok' => true,
            'updated' => $result['updated'] ?? false,
            'updated_ids' => $result['updated_ids'] ?? [],
            'insert_id' => $result['insert_id'] ?? null,
        ]);
    }

    public function byParent(InvoiceParentRequest $request, int $parentId): JsonResponse
    {
        $schoolYear = $request->validated()['school_year'] ?? null;
        $invoices = Invoice::getInvoicesByParentId($parentId, $schoolYear);

        return response()->json([
            'ok' => true,
            'invoices' => InvoiceResource::collection($invoices),
        ]);
    }

    public function parentPayment(InvoiceParentRequest $request): JsonResponse
    {
        $parentId = (int) (auth()->id() ?? 0);
        if ($parentId <= 0) {
            return response()->json(['ok' => false, 'message' => 'Unauthorized.'], 401);
        }

        $schoolYear = $request->validated()['school_year'] ?? null;
        $data = $this->paymentService->getParentInvoiceSummary($parentId, $schoolYear);

        return response()->json([
            'ok' => true,
            'invoices' => InvoiceResource::collection($data['invoices']),
            'schoolYears' => $data['schoolYears'],
            'selectedYear' => $data['selectedYear'],
            'currentSchoolYear' => $data['currentSchoolYear'],
            'dueDate' => $data['dueDate'],
        ]);
    }

    public function updateStatus(InvoiceStatusRequest $request, int $invoiceId): JsonResponse
    {
        $status = $request->validated()['status'];
        $updated = Invoice::updateInvoiceStatus($invoiceId, $status);

        if (!$updated) {
            return response()->json(['ok' => false, 'message' => 'Invoice not found.'], 404);
        }

        return response()->json(['ok' => true, 'status' => $status]);
    }

    public function unpaid(): JsonResponse
    {
        $rows = Invoice::getUnpaidInvoices();

        return response()->json([
            'ok' => true,
            'invoices' => InvoiceResource::collection($rows),
        ]);
    }

    public function pdf(int $invoiceId): StreamedResponse
    {
        $pdfBytes = $this->pdfService->buildPdf($invoiceId);

        return response()->streamDownload(function () use ($pdfBytes) {
            echo $pdfBytes;
        }, 'invoice_' . $invoiceId . '.pdf', ['Content-Type' => 'application/pdf']);
    }
}
