<?php

declare(strict_types=1);

namespace App\Http\Controllers\Barangay;

use App\Enums\UserActions;
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
use App\Http\Controllers\Helpers\ResponseHelper;
use App\Models\Barangay\Resident;
use App\Models\User;
use Hypervel\Http\Request;
use Hypervel\Support\Facades\Auth;
use Hypervel\Support\Facades\Validator;

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

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

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

        $query = Resident::with('user')->orderByDesc('id');

        if ($search = $request->input('search')) {
            $query->where(function ($q) use ($search) {
                $q->where('firstname', 'like', "%{$search}%")
                  ->orWhere('lastname', 'like', "%{$search}%")
                  ->orWhere('middlename', 'like', "%{$search}%");
            });
        }

        if ($purok = $request->input('purok')) $query->where('purok', $purok);
        if ($request->input('active_only')) $query->active();

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

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

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

        $resident = Resident::with(['user', 'householdMemberships.household'])
            ->where('hashkey', $request->input('target'))
            ->first();

        if (!$resident) return ResponseHelper::returnError('Resident not found', 404);

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

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

        $validator = Validator::make($request->all(), [
            'firstname'    => 'required|string|max:100',
            'lastname'     => 'required|string|max:100',
            'middlename'   => 'nullable|string|max:100',
            'suffix'       => 'nullable|string|max:20',
            'dob'          => 'required|date',
            'birthplace'   => 'nullable|string|max:255',
            'gender'       => 'required|in:MALE,FEMALE,OTHER',
            'civil_status' => 'required|in:SINGLE,MARRIED,WIDOWED,SEPARATED,ANNULLED',
            'citizenship'  => 'nullable|string|max:100',
            'religion'     => 'nullable|string|max:100',
            'occupation'   => 'nullable|string|max:255',
            'monthly_income'    => 'nullable|numeric|min:0',
            'blood_type'        => 'nullable|string|max:5',
            'voter_status'      => 'nullable|boolean',
            'head_of_household' => 'nullable|boolean',
            'purok'    => 'nullable|string|max:100',
            'street'   => 'nullable|string|max:255',
            'barangay' => 'nullable|string|max:100',
            'city'     => 'nullable|string|max:100',
            'province' => 'nullable|string|max:100',
            'region'   => 'nullable|string|max:100',
            'philhealth_id' => 'nullable|string|max:50',
            'sss_id'        => 'nullable|string|max:50',
            'gsis_id'       => 'nullable|string|max:50',
            'tin'           => 'nullable|string|max:50',
            'emergency_contact_name'    => 'nullable|string|max:255',
            'emergency_contact_phone'   => 'nullable|string|max:30',
            'emergency_contact_address' => 'nullable|string|max:255',
            'user_id'  => 'nullable|integer|exists:users,id',
        ]);

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

        $data = $validator->validated();
        $data['hashkey'] = hash('sha256', uniqid((string) now(), true));
        $data['is_active'] = true;
        $data['created_by'] = Auth::id();
        $data['updated_by'] = Auth::id();

        $resident = Resident::create($data);

        return response()->json(['success' => true, 'data' => $resident, 'message' => 'Resident created']);
    }

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

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

        $data = $request->except(['target', 'hashkey', 'created_by']);
        $data['updated_by'] = Auth::id();
        $resident->update($data);

        return response()->json(['success' => true, 'data' => $resident, 'message' => 'Resident updated']);
    }

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

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

        $resident->update(['is_active' => (bool) $request->input('active', true)]);

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

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

        $term = $request->input('q', '');
        $residents = Resident::where(function ($q) use ($term) {
            $q->where('firstname', 'like', "%{$term}%")
              ->orWhere('lastname', 'like', "%{$term}%")
              ->orWhere('middlename', 'like', "%{$term}%");
        })->active()->limit(20)->get(['id', 'hashkey', 'firstname', 'middlename', 'lastname', 'suffix', 'purok', 'dob']);

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

    public function puroks()
    {
        $puroks = Resident::distinct()->orderBy('purok')->pluck('purok')->filter()->values();
        return response()->json(['success' => true, 'data' => $puroks]);
    }
}
