<?php

namespace App\Master\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Mail\ImpersonationRequestActionedMail;
use App\Mail\ImpersonationRequestCreatedMail;
use App\Master\Models\ImpersonationRequest;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Mtc\MercuryDataModels\User;

class ImpersonationRequestController extends Controller
{
    public function index(Request $request): JsonResponse
    {
        $status = $request->input('status');
        $perPage = $request->input('per_page', 25);

        $data = ImpersonationRequest::query()
            ->with(['requester', 'targetUser', 'actionedBy'])
            ->when(
                $status && $status !== '',
                fn ($query) => $query->where('status', $status)
            )
            ->latest()
            ->paginate($perPage)
            ->through(fn (ImpersonationRequest $item) => [
                'id' => $item->id,
                'name' => $item->requester?->name ?? 'Unknown',
                'description' => $item->targetUser?->name ?? 'Unknown',
                'reason' => $item->reason,
                'status' => $item->status,
                'requester' => [
                    'id' => $item->requester?->id,
                    'name' => $item->requester?->name,
                    'email' => $item->requester?->email,
                ],
                'target_user' => [
                    'id' => $item->targetUser?->id,
                    'name' => $item->targetUser?->name,
                    'email' => $item->targetUser?->email,
                ],
                'actioned_by' => $item->actionedBy ? [
                    'name' => $item->actionedBy->name,
                ] : null,
                'admin_notes' => $item->admin_notes,
                'expires_at' => $item->expires_at?->toISOString(),
                'used_at' => $item->used_at?->toISOString(),
                'created_at' => $item->created_at?->format('d/m/Y H:i'),
                'metaItems' => [
                    ucfirst($item->status),
                    $item->created_at?->format('d/m/Y H:i') ?? '-',
                ],
            ])
            ->toArray();

        return response()->json($data);
    }

    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'target_user_id' => 'required|exists:users,id',
            'reason' => 'required|string|max:1000',
        ]);

        $user = $request->user();

        if ($validated['target_user_id'] == $user->id) {
            return response()->json([
                'message' => 'You cannot request to impersonate yourself.',
            ], 422);
        }

        $targetUser = User::findOrFail($validated['target_user_id']);

        if ($targetUser->hasRole('mtc')) {
            return response()->json([
                'message' => 'You cannot request to impersonate a superadmin user.',
            ], 422);
        }

        $existingRequest = ImpersonationRequest::query()
            ->where('requester_id', $user->id)
            ->where('target_user_id', $validated['target_user_id'])
            ->pending()
            ->first();

        if ($existingRequest) {
            return response()->json([
                'message' => 'A pending impersonation request for this user already exists.',
            ], 422);
        }

        $impersonationRequest = ImpersonationRequest::create([
            'requester_id' => $user->id,
            'target_user_id' => $validated['target_user_id'],
            'reason' => $validated['reason'],
            'status' => 'pending',
            'session_id' => session()->getId(),
        ]);

        $impersonationRequest->load(['requester', 'targetUser']);

        $approvers = User::permission('approve-impersonation')->get();
        foreach ($approvers as $approver) {
            Mail::to($approver->email)
                ->send(new ImpersonationRequestCreatedMail($impersonationRequest));
        }

        return response()->json([
            'message' => 'Impersonation request submitted successfully.',
            'request' => $impersonationRequest,
        ], 201);
    }

    public function approve(Request $request, int $id): JsonResponse
    {
        $user = $request->user();

        if (!$user->hasPermissionTo('approve-impersonation')) {
            return response()->json([
                'message' => 'You do not have permission to approve impersonation requests.',
            ], 403);
        }

        $impersonationRequest = ImpersonationRequest::findOrFail($id);

        if (!$impersonationRequest->isPending()) {
            return response()->json([
                'message' => 'This request has already been processed.',
            ], 422);
        }

        if ($impersonationRequest->requester_id === $user->id) {
            return response()->json([
                'message' => 'You cannot approve your own impersonation request.',
            ], 422);
        }

        $validated = $request->validate([
            'admin_notes' => 'nullable|string|max:1000',
        ]);

        $impersonationRequest->update([
            'status' => 'approved',
            'actioned_by' => $user->id,
            'actioned_at' => now(),
            'expires_at' => now()->addHour(),
            'admin_notes' => $validated['admin_notes'] ?? null,
        ]);

        $impersonationRequest->load(['requester', 'targetUser', 'actionedBy']);

        Mail::to($impersonationRequest->requester->email)
            ->send(new ImpersonationRequestActionedMail($impersonationRequest));

        return response()->json([
            'message' => 'Impersonation request approved.',
            'request' => $impersonationRequest,
        ]);
    }

    public function reject(Request $request, int $id): JsonResponse
    {
        $user = $request->user();

        if (!$user->hasPermissionTo('approve-impersonation')) {
            return response()->json([
                'message' => 'You do not have permission to reject impersonation requests.',
            ], 403);
        }

        $validated = $request->validate([
            'admin_notes' => 'required|string|max:1000',
        ]);

        $impersonationRequest = ImpersonationRequest::findOrFail($id);

        if (!$impersonationRequest->isPending()) {
            return response()->json([
                'message' => 'This request has already been processed.',
            ], 422);
        }

        $impersonationRequest->update([
            'status' => 'rejected',
            'actioned_by' => $user->id,
            'actioned_at' => now(),
            'admin_notes' => $validated['admin_notes'],
        ]);

        $impersonationRequest->load(['requester', 'targetUser', 'actionedBy']);

        Mail::to($impersonationRequest->requester->email)
            ->send(new ImpersonationRequestActionedMail($impersonationRequest));

        return response()->json([
            'message' => 'Impersonation request rejected.',
            'request' => $impersonationRequest,
        ]);
    }
}
