<?php

namespace App\Http\Controllers\Api;

use App\Enums\UserRole;
use App\Enums\VisitorStatus;
use App\Helpers\ApiResponse;
use App\Http\Controllers\Controller;
use App\Http\Requests\Visitor\StoreVisitorRequest;
use App\Http\Requests\Visitor\UpdateVisitorRequest;
use App\Http\Requests\Visitor\ApproveVisitorRequest;
use App\Http\Requests\Visitor\RejectVisitorRequest;
use App\Http\Resources\VisitorResource;
use App\Models\Visitor;
use App\Models\Flat;
use App\Models\User;
use App\Traits\CanManageFile;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Spatie\QueryBuilder\QueryBuilder;

class VisitorController extends Controller
{
    use CanManageFile;

    public function __construct()
    {
        $this->resourceName = 'visitors';
        $this->fileFieldNames = ['photo'];
        $this->fileFolderPaths = ['photos'];
    }

    public function index()
    {
        $query = QueryBuilder::for(Visitor::class)
            ->allowedFilters(['name', 'phone', 'status', 'visitor_type', 'wing_id', 'flat_id', 'approved_by'])
            ->allowedIncludes(['wing', 'flat', 'approvedBy', 'checkedInBy', 'checkedOutBy'])
            ->allowedSorts(['created_at', 'entry_time', 'exit_time', 'approved_at'])
            ->latest();

        $user = auth()->user();

        if ($user->role == UserRole::OWNER || $user->role == UserRole::USER) {
            $query->where('flat_id', $user->flat_id);
        }

        $visitors = $query->paginate(request("perPage", 15));

        return ApiResponse::paginated($visitors);
    }

    public function store(StoreVisitorRequest $request)
    {
        $visitor = new Visitor($request->validated());
        $this->storeFiles($request, $visitor);
        $visitor->save();

        return ApiResponse::created(
            new VisitorResource($visitor->load(['wing', 'flat'])),
            "Visitor request has been submitted successfully!"
        );
    }

    public function show(Visitor $visitor)
    {
        return ApiResponse::resource(
            new VisitorResource($visitor->load(['wing', 'flat', 'approvedBy', 'checkedInBy', 'checkedOutBy']))
        );
    }

    public function update(UpdateVisitorRequest $request, Visitor $visitor)
    {
        if ($visitor->isApproved() || $visitor->isRejected()) {
            return ApiResponse::error('Cannot update visitor request after approval/rejection.', 422);
        }

        $visitor->fill($request->validated());
        $this->updateFiles($request, $visitor);
        $visitor->save();

        return ApiResponse::updated(
            new VisitorResource($visitor->load(['wing', 'flat'])),
            "Visitor request has been updated successfully!"
        );
    }

    public function destroy(Visitor $visitor)
    {
        if ($visitor->isCheckedIn()) {
            return ApiResponse::error('Cannot delete visitor who is currently checked in.', 422);
        }

        $this->deleteFiles($visitor);

        $visitor->delete();

        return ApiResponse::deleted("Visitor request has been deleted successfully!");
    }

    public function approve(ApproveVisitorRequest $request, Visitor $visitor)
    {
        if (!$visitor->isPending()) {
            return ApiResponse::error('Only pending visitor requests can be approved.', 400);
        }

        $flat = Flat::find($visitor->flat_id);
        $user = auth()->user();

        if (!$this->canApproveVisitor($user, $flat)) {
            return ApiResponse::forbidden('You are not authorized to approve visitors for this flat.');
        }

        $visitor->update([
            'status' => VisitorStatus::APPROVED,
            'approved_by' => $user->id,
            'approved_at' => now(),
            'approval_notes' => $request->approval_notes,
        ]);

        return ApiResponse::success(
            new VisitorResource($visitor->load(['wing', 'flat', 'approvedBy'])),
            "Visitor request has been approved successfully!"
        );
    }

    public function reject(RejectVisitorRequest $request, Visitor $visitor)
    {
        if (!$visitor->isPending()) {
            return ApiResponse::error('Only pending visitor requests can be rejected.', 422);
        }

        $flat = Flat::find($visitor->flat_id);
        $user = auth()->user();

        if (!$this->canApproveVisitor($user, $flat)) {
            return ApiResponse::forbidden('You are not authorized to reject visitors for this flat.');
        }

        $visitor->update([
            'status' => VisitorStatus::REJECTED,
            'approved_by' => $user->id,
            'approved_at' => now(),
            'rejection_reason' => $request->rejection_reason,
        ]);

        return ApiResponse::success(
            new VisitorResource($visitor->load(['wing', 'flat', 'approvedBy'])),
            "Visitor request has been rejected successfully!"
        );
    }

    public function checkIn(Request $request, Visitor $visitor)
    {
        if (!$visitor->isApproved()) {
            return ApiResponse::error('Only approved visitor requests can be checked in.', statusCode: 400);
        }

        $visitor->update([
            'status' => VisitorStatus::CHECKED_IN,
            'entry_time' => now(),
            'checked_in_by' => auth()->user()->id,
        ]);

        return ApiResponse::success(
            new VisitorResource($visitor->load(['wing', 'flat', 'checkedInBy'])),
            "Visitor has been checked in successfully!"
        );
    }

    public function checkOut(Request $request, Visitor $visitor)
    {
        if (!$visitor->canCheckOut()) {
            return ApiResponse::error('Only chacked in visitor requests can be checked out.', 422);
        }

        $visitor->update([
            'status' => VisitorStatus::CHECKED_OUT,
            'exit_time' => now(),
            'checked_out_by' => auth()->user()->id,
        ]);

        return ApiResponse::success(
            new VisitorResource($visitor->load(['wing', 'flat', 'checkedOutBy'])),
            "Visitor has been checked out successfully!"
        );
    }

    public function pending()
    {
        $user = auth()->user();
        $userFlats = $this->getUserFlats($user);

        $query = QueryBuilder::for(Visitor::class)
            ->where('status', VisitorStatus::PENDING)
            ->whereIn('flat_id', $userFlats)
            ->allowedFilters(['name', 'phone', 'visitor_type', 'wing_id', 'flat_id'])
            ->allowedIncludes(['wing', 'flat'])
            ->latest();

        $visitors = $query->paginate(request("perPage", 15));

        return ApiResponse::paginated($visitors);
    }

    public function today()
    {
        $today = now()->format('Y-m-d');

        $query = QueryBuilder::for(Visitor::class)
            ->where(function($q) use ($today) {
                $q->whereDate('entry_time', $today);
            })
            ->allowedFilters(['status', 'visitor_type', 'wing_id', 'flat_id'])
            ->allowedIncludes(['wing', 'flat', 'approvedBy', 'checkedInBy', 'checkedOutBy'])
            ->latest();

        $visitors = $query->paginate(request("perPage", 15));

        return ApiResponse::paginated($visitors);
    }

    public function myVisitors()
    {
        $user = auth()->user();
        $userFlats = $this->getUserFlats($user);

        $query = QueryBuilder::for(Visitor::class)
            ->whereIn('flat_id', $userFlats)
            ->allowedFilters(['status', 'visitor_type', 'wing_id', 'flat_id'])
            ->allowedIncludes(['wing', 'flat', 'approvedBy', 'checkedInBy', 'checkedOutBy'])
            ->latest();

        $visitors = $query->paginate(request("perPage", 15));

        return ApiResponse::paginated($visitors);
    }

    private function canApproveVisitor(User $user, Flat $flat): bool
    {
        return $flat->owner_id === $user->owner_id;
    }

    private function getUserFlats(User $user): array
    {
        return Flat::where('owner_id', $user->owner_id)
            ->pluck('id')
            ->toArray();
    }
}
