<?php

namespace App\Http\Controllers;

use App\Facades\Settings;
use App\Http\Requests\RequestSiteAccessRequest;
use App\Http\Resources\SiteResource;
use App\Services\Geolocation\CurrencyDetector;
use App\Traits\CacheObject;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Mtc\MercuryDataModels\SiteAccessRequest as SiteAccessRequestModel;

class SiteController extends Controller
{
    use CacheObject;

    public function index(Request $request, CurrencyDetector $detector): SiteResource|Response|JsonResponse|array
    {
        $response = $this->cache('get-site', 5, fn () => new SiteResource([])->toResponse($request));

        return $this->appendDetectedCurrency($response, $detector->detect($request));
    }

    public function checkAccess(Request $request)
    {
        if ($this->accessMode() !== 'password') {
            return response('Access Denied', 403);
        }

        return $request->input('password') === Settings::get('site-access-password')
            ? response('Access Granted')
            : response('Access Denied', 403);
    }

    public function requestAccess(RequestSiteAccessRequest $request): JsonResponse
    {
        $email = strtolower(trim((string) $request->input('email')));

        if (Settings::get('site-access-enabled') && $this->accessMode() === 'email-request') {
            if ($this->isWhitelistedEmail($email)) {
                SiteAccessRequestModel::create([
                    'email' => $email,
                    'ip' => $request->ip(),
                    'user_agent' => Str::limit((string) $request->userAgent(), 250, ''),
                ]);
            } else {
                Log::info('Site access request rejected (domain not whitelisted)', [
                    'email' => $email,
                    'ip' => $request->ip(),
                ]);
            }
        }

        return response()->json([
            'message' => 'If your email is permitted, you will receive a link shortly.',
        ]);
    }

    public function verifyAccessToken(Request $request): JsonResponse
    {
        $token = (string) $request->input('token');

        if (!preg_match('/^[A-Za-z0-9]{64}$/', $token)) {
            return response()->json(['success' => false], 410);
        }

        $accessRequest = SiteAccessRequestModel::query()->valid()->where('token', $token)->first();

        if (!$accessRequest) {
            return response()->json(['success' => false], 410);
        }

        if ($accessRequest->used_at === null) {
            $accessRequest->forceFill(['used_at' => Carbon::now()])->save();
        }

        return response()->json(['success' => true]);
    }

    private function accessMode(): string
    {
        return Settings::get('site-access-mode') ?: 'password';
    }

    private function isWhitelistedEmail(string $email): bool
    {
        $domain = Str::after($email, '@');

        if ($domain === '' || $domain === $email) {
            return false;
        }

        $whitelist = Str::of((string) Settings::get('site-access-whitelisted-domains'))
            ->explode(',')
            ->map(fn (string $entry) => strtolower(trim($entry)))
            ->filter()
            ->values();

        return $whitelist->contains($domain);
    }

    private function appendDetectedCurrency(
        SiteResource|Response|JsonResponse|array $response,
        ?string $detectedCurrency
    ): SiteResource|Response|JsonResponse|array {
        if (!$response instanceof JsonResponse) {
            return $response;
        }

        $data = $response->getData(true);
        if (!is_array($data)) {
            return $response;
        }

        $data['detected_currency'] = $detectedCurrency;

        return response()->json($data, $response->getStatusCode(), $response->headers->all());
    }
}
