<?php

namespace App\Http\Controllers\Api\Expenses;

use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Expenses\StoreExpenseRequest;
use App\Http\Requests\Expenses\UpdateExpenseRequest;
use App\Http\Requests\Expenses\UpdateExpenseStatusRequest;
use App\Http\Resources\Expenses\ExpenseResource;
use App\Http\Resources\Expenses\ExpenseStaffResource;
use App\Models\Expense;
use App\Services\Expenses\ExpenseContextService;
use App\Services\Expenses\ExpenseQueryService;
use App\Services\Expenses\ExpenseReceiptService;
use App\Services\Expenses\ExpenseRetailorService;
use App\Services\Expenses\ExpenseStaffService;
use App\Services\Expenses\ExpenseStatusService;
use App\Services\Expenses\ExpenseWriteService;
use Illuminate\Http\JsonResponse;

class ExpenseController extends BaseApiController
{
    public function __construct(
        private ExpenseContextService $context,
        private ExpenseRetailorService $retailors,
        private ExpenseStaffService $staff,
        private ExpenseQueryService $queryService,
        private ExpenseReceiptService $receiptService,
        private ExpenseWriteService $writeService,
        private ExpenseStatusService $statusService
    ) {
        parent::__construct();
    }

    public function options(): JsonResponse
    {
        $schoolYear = $this->context->getSchoolYear();
        $semester = $this->context->getSemester();

        return response()->json([
            'ok' => true,
            'schoolYear' => $schoolYear,
            'semester' => $semester,
            'retailors' => $this->retailors->listRetailors(),
            'staff' => ExpenseStaffResource::collection($this->staff->listStaffUsers()),
        ]);
    }

    public function index(): JsonResponse
    {
        $rows = $this->queryService->listAll();
        $rows = array_map(function ($row) {
            $row['receipt_url'] = $this->receiptService->receiptUrl($row['receipt_path'] ?? null);
            return $row;
        }, $rows);

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

    public function show(int $id): JsonResponse
    {
        $row = $this->queryService->findById($id);
        if (!$row) {
            return response()->json(['ok' => false, 'message' => 'Expense not found.'], 404);
        }

        $row['receipt_url'] = $this->receiptService->receiptUrl($row['receipt_path'] ?? null);

        return response()->json([
            'ok' => true,
            'expense' => new ExpenseResource($row),
        ]);
    }

    public function store(StoreExpenseRequest $request): JsonResponse
    {
        $payload = $request->validated();
        $userId = (int) (auth()->id() ?? 0);

        $receiptName = null;
        if ($request->hasFile('receipt')) {
            $receiptName = $this->receiptService->storeReceipt($request->file('receipt'));
        }

        $isDonation = $payload['category'] === 'Donation';

        $expense = $this->writeService->store([
            'category' => $payload['category'],
            'amount' => $payload['amount'],
            'receipt_path' => $receiptName,
            'description' => $payload['description'] ?? null,
            'retailor' => $payload['retailor'] ?? null,
            'date_of_purchase' => $payload['date_of_purchase'],
            'purchased_by' => (int) $payload['purchased_by'],
            'added_by' => $userId,
            'status' => $isDonation ? 'approved' : 'pending',
            'status_reason' => $isDonation ? 'Marked as Donation (non-reimbursable).' : null,
            'approved_by' => $isDonation ? $userId : null,
            'school_year' => $payload['school_year'] ?? null,
            'semester' => $payload['semester'] ?? null,
        ]);

        return response()->json([
            'ok' => true,
            'expense' => new ExpenseResource($expense->toArray()),
        ], 201);
    }

    public function update(UpdateExpenseRequest $request, int $id): JsonResponse
    {
        $expense = Expense::query()->find($id);
        if (!$expense) {
            return response()->json(['ok' => false, 'message' => 'Expense not found.'], 404);
        }

        $payload = $request->validated();
        $userId = (int) (auth()->id() ?? 0);

        $receiptName = $expense->receipt_path;
        if ($request->hasFile('receipt')) {
            $receiptName = $this->receiptService->storeReceipt($request->file('receipt'));
        }
        if (!empty($payload['remove_receipt'])) {
            $receiptName = null;
        }

        $category = $payload['category'];
        $isDonation = $category === 'Donation';

        $updateData = [
            'category' => $category,
            'amount' => $payload['amount'],
            'description' => $payload['description'] ?? null,
            'retailor' => $payload['retailor'] ?? null,
            'date_of_purchase' => $payload['date_of_purchase'],
            'purchased_by' => (int) $payload['purchased_by'],
            'receipt_path' => $receiptName,
            'updated_by' => $userId,
        ];

        if ($isDonation) {
            $updateData['status'] = 'approved';
            $updateData['status_reason'] = 'Marked as Donation (non-reimbursable).';
            $updateData['approved_by'] = $userId ?: null;
            $updateData['reimbursement_id'] = null;
        } elseif (($expense->category ?? '') === 'Donation') {
            $updateData['status_reason'] = null;
            $updateData['approved_by'] = $expense->approved_by;
            $updateData['status'] = $expense->status ?? 'pending';
        }

        $updated = $this->writeService->update($expense, $updateData);

        return response()->json([
            'ok' => true,
            'expense' => new ExpenseResource($updated->toArray()),
        ]);
    }

    public function updateStatus(UpdateExpenseStatusRequest $request, int $id): JsonResponse
    {
        $expense = Expense::query()->find($id);
        if (!$expense) {
            return response()->json(['ok' => false, 'message' => 'Expense not found.'], 404);
        }

        $payload = $request->validated();
        $userId = (int) (auth()->id() ?? 0);

        $updated = $this->statusService->updateStatus($expense, $payload['status'], $payload['reason'] ?? '', $userId);

        return response()->json([
            'ok' => true,
            'expense' => new ExpenseResource($updated->toArray()),
        ]);
    }
}
