<?php

namespace App\Master\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Mail\LiveSiteAccessRequestActionedMail;
use App\Mail\LiveSiteAccessRequestCreatedMail;
use App\Master\Http\Requests\CreateLiveSiteAccessRequest;
use App\Master\Models\LiveSiteAccessRequest;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Mtc\MercuryDataModels\Tenant;
use Mtc\MercuryDataModels\User;

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

        $data = LiveSiteAccessRequest::query()
            ->with(['requester', 'actionedBy', 'tenant'])
            ->when(
                $status && $status !== '',
                fn ($query) => $query->where('status', $status)
            )
            ->latest()
            ->paginate($perPage)
            ->through(fn (LiveSiteAccessRequest $item) => $this->transform($item))
            ->toArray();

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

    public function store(CreateLiveSiteAccessRequest $request): JsonResponse
    {
        $user = $request->user();

        $existing = LiveSiteAccessRequest::query()
            ->where('requester_id', $user->id)
            ->where('tenant_id', $request->input('tenant_id'))
            ->pending()
            ->first();

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

        $accessRequest = LiveSiteAccessRequest::create([
            'requester_id' => $user->id,
            'tenant_id' => $request->input('tenant_id'),
            'reason' => $request->input('reason'),
            'status' => 'pending',
        ]);

        $accessRequest->load(['requester', 'tenant']);

        $approvers = User::permission('approve-live-site-access')->get();
        foreach ($approvers as $approver) {
            Mail::to($approver->email)
                ->send(new LiveSiteAccessRequestCreatedMail($accessRequest));
        }

        return response()->json([
            'message' => 'Live site access request submitted successfully.',
            'request' => $this->transform($accessRequest),
        ], 201);
    }

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

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

        $accessRequest = LiveSiteAccessRequest::findOrFail($id);

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

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

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

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

        $accessRequest->load(['requester', 'actionedBy', 'tenant']);

        Mail::to($accessRequest->requester->email)
            ->send(new LiveSiteAccessRequestActionedMail($accessRequest));

        return response()->json([
            'message' => 'Live site access request approved.',
            'request' => $this->transform($accessRequest),
        ]);
    }

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

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

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

        $accessRequest = LiveSiteAccessRequest::findOrFail($id);

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

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

        $accessRequest->load(['requester', 'actionedBy', 'tenant']);

        Mail::to($accessRequest->requester->email)
            ->send(new LiveSiteAccessRequestActionedMail($accessRequest));

        return response()->json([
            'message' => 'Live site access request rejected.',
            'request' => $this->transform($accessRequest),
        ]);
    }

    private function transform(LiveSiteAccessRequest $item): array
    {
        $tenant = $item->tenant ?? Tenant::find($item->tenant_id);

        return [
            'id' => $item->id,
            'reason' => $item->reason,
            'status' => $item->status,
            'requester' => [
                'id' => $item->requester?->id,
                'name' => $item->requester?->name,
                'email' => $item->requester?->email,
            ],
            'tenant' => [
                'id' => $item->tenant_id,
                'name' => $tenant?->name,
            ],
            'actioned_by' => $item->actionedBy ? [
                'name' => $item->actionedBy->name,
            ] : null,
            'admin_notes' => $item->admin_notes,
            'expires_at' => $item->expires_at?->toISOString(),
            'first_used_at' => $item->first_used_at?->toISOString(),
            'last_used_at' => $item->last_used_at?->toISOString(),
            'is_expired' => $item->isExpired(),
            'created_at' => $item->created_at?->format('d/m/Y H:i'),
        ];
    }
}
