<?php

declare(strict_types=1);

namespace App\Http\Controllers\Barangay;

use App\Enums\UserActions;
use App\Enums\Barangay\DocumentStatus;
use App\Enums\Barangay\PaymentStatus;
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
use App\Http\Controllers\Helpers\ResponseHelper;
use App\Models\Barangay\DocumentRequest;
use App\Models\Barangay\RequestPayment;
use App\Models\Barangay\RequestType;
use Hypervel\Http\Request;
use Hypervel\Support\Facades\Auth;
use Hypervel\Support\Facades\Validator;

class DocumentRequestController
{
    private function checkRead(): bool
    {
        return UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::ViewDocumentRequests);
    }

    private function checkWrite(): bool
    {
        return UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::ProcessDocumentRequest);
    }

    public function index(Request $request)
    {
        if (!$this->checkRead()) return ResponseHelper::returnUnauthorized();

        $query = DocumentRequest::with(['requestType', 'resident', 'processedBy'])->orderByDesc('id');

        if ($status = $request->input('status')) $query->where('status', $status);
        if ($payStatus = $request->input('payment_status')) $query->where('payment_status', $payStatus);
        if ($typeId = $request->input('request_type_id')) $query->where('request_type_id', $typeId);
        if ($search = $request->input('search')) {
            $query->where('request_no', 'like', "%{$search}%");
        }

        $requests = $query->paginate((int) $request->input('per_page', 20));

        return response()->json(['success' => true, 'data' => $requests]);
    }

    public function myRequests(Request $request)
    {
        $requests = DocumentRequest::with('requestType')
            ->where('resident_user_id', Auth::id())
            ->orderByDesc('id')
            ->get();

        return response()->json(['success' => true, 'data' => $requests]);
    }

    public function show(Request $request)
    {
        if (!$this->checkRead()) return ResponseHelper::returnUnauthorized();

        $doc = DocumentRequest::with(['requestType', 'resident', 'processedBy', 'payments'])
            ->where('hashkey', $request->input('target'))
            ->first();

        if (!$doc) return ResponseHelper::returnError('Request not found', 404);

        return response()->json(['success' => true, 'data' => $doc]);
    }

    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'request_type_id' => 'required|integer|exists:barangay_request_types,id',
            'purpose'         => 'required|string|max:500',
        ]);

        if ($validator->fails()) {
            return response()->json(['success' => false, 'errors' => $validator->errors()], 422);
        }

        $reqType = RequestType::findOrFail($request->input('request_type_id'));

        $doc = DocumentRequest::create([
            'hashkey'          => hash('sha256', uniqid((string) now(), true)),
            'request_no'       => DocumentRequest::generateRequestNo(),
            'resident_user_id' => Auth::id(),
            'request_type_id'  => $reqType->id,
            'purpose'          => $request->input('purpose'),
            'fee_amount'       => $reqType->base_fee,
            'payment_status'   => PaymentStatus::PENDING,
            'status'           => $reqType->base_fee > 0 ? DocumentStatus::PENDING_PAYMENT : DocumentStatus::PAID,
            'requested_by'     => Auth::id(),
        ]);

        return response()->json(['success' => true, 'data' => $doc, 'message' => 'Document request submitted']);
    }

    public function updateStatus(Request $request)
    {
        if (!$this->checkWrite()) return ResponseHelper::returnUnauthorized();

        $doc = DocumentRequest::where('hashkey', $request->input('target'))->first();
        if (!$doc) return ResponseHelper::returnError('Request not found', 404);

        $newStatus = DocumentStatus::tryFrom($request->input('status'));
        if (!$newStatus) return ResponseHelper::returnError('Invalid status', 422);

        $data = [
            'status'       => $newStatus,
            'processed_by' => Auth::id(),
        ];

        if ($newStatus === DocumentStatus::CLAIMED) {
            $data['claimed_at'] = now();
        }

        if ($request->input('notes')) $data['notes'] = $request->input('notes');

        $doc->update($data);

        return response()->json(['success' => true, 'data' => $doc, 'message' => 'Status updated to ' . $newStatus->label()]);
    }

    public function confirmPayment(Request $request)
    {
        if (!$this->checkWrite()) return ResponseHelper::returnUnauthorized();

        $doc = DocumentRequest::where('hashkey', $request->input('target'))->first();
        if (!$doc) return ResponseHelper::returnError('Request not found', 404);

        $validator = Validator::make($request->all(), [
            'method'    => 'required|in:CASH,GCASH,QRPH,BANK,WAIVED',
            'reference' => 'nullable|string|max:100',
            'amount'    => 'nullable|numeric|min:0',
        ]);

        if ($validator->fails()) {
            return response()->json(['success' => false, 'errors' => $validator->errors()], 422);
        }

        $method = $request->input('method');
        $amount = $request->input('amount', $doc->fee_amount);

        RequestPayment::create([
            'request_id'  => $doc->id,
            'amount'      => $amount,
            'method'      => $method,
            'reference'   => $request->input('reference'),
            'paid_at'     => now(),
            'verified_by' => Auth::id(),
        ]);

        $doc->update([
            'payment_status' => PaymentStatus::PAID,
            'payment_method' => $method,
            'payment_ref'    => $request->input('reference'),
            'status'         => DocumentStatus::PROCESSING,
            'processed_by'   => Auth::id(),
        ]);

        return response()->json(['success' => true, 'data' => $doc, 'message' => 'Payment confirmed']);
    }

    public function markReady(Request $request)
    {
        if (!$this->checkWrite()) return ResponseHelper::returnUnauthorized();

        $doc = DocumentRequest::where('hashkey', $request->input('target'))->first();
        if (!$doc) return ResponseHelper::returnError('Request not found', 404);

        $doc->update(['status' => DocumentStatus::READY, 'processed_by' => Auth::id()]);

        return response()->json(['success' => true, 'data' => $doc, 'message' => 'Marked as ready for pickup']);
    }

    public function markClaimed(Request $request)
    {
        if (!$this->checkWrite()) return ResponseHelper::returnUnauthorized();

        $doc = DocumentRequest::where('hashkey', $request->input('target'))->first();
        if (!$doc) return ResponseHelper::returnError('Request not found', 404);

        $doc->update([
            'status'     => DocumentStatus::CLAIMED,
            'claimed_at' => now(),
        ]);

        return response()->json(['success' => true, 'data' => $doc, 'message' => 'Document marked as claimed']);
    }

    public function cancel(Request $request)
    {
        $doc = DocumentRequest::where('hashkey', $request->input('target'))->first();
        if (!$doc) return ResponseHelper::returnError('Request not found', 404);

        if ($doc->resident_user_id !== Auth::id() && !$this->checkWrite()) {
            return ResponseHelper::returnUnauthorized();
        }

        if (in_array($doc->status, [DocumentStatus::CLAIMED, DocumentStatus::CANCELLED])) {
            return ResponseHelper::returnError('Cannot cancel this request', 422);
        }

        $doc->update(['status' => DocumentStatus::CANCELLED]);

        return response()->json(['success' => true, 'message' => 'Request cancelled']);
    }
}
