<?php

namespace App\Controllers;

use App\Services\AuthSessionService;
use App\Services\OtpService;
use App\Services\PersistentLoginService;
use App\Support\EmailAddress;

class AuthController extends BaseController
{
    public function entry()
    {
        $auth = new AuthSessionService();

        if (! session()->get('user_id')) {
            (new PersistentLoginService())->restoreSessionIfValid();
        }

        if (session()->get('user_id')) {
            return redirect()->to($auth->authenticatedDestination())->withCookies();
        }

        return redirect()->to('/sign-in');
    }

    public function index()
    {
        return view('auth/sign_in', [
            'title' => 'Sign In',
            'email' => old('email'),
        ]);
    }

    public function sendOtp()
    {
        $email  = EmailAddress::normalize((string) $this->request->getPost('email'));
        $result = (new OtpService())->send($email);

        if (! ($result['ok'] ?? false)) {
            return $this->authError($result['message'] ?? OtpService::MSG_SEND_FAIL, $email);
        }

        session()->set('otp_email', $result['email']);
        session()->set('otp_sent_at', time());

        return redirect()->to('/auth/verify-otp')->with('otp_sent', true);
    }

    public function verifyForm()
    {
        $email = (string) session()->get('otp_email');
        if ($email === '') {
            return redirect()->to('/sign-in');
        }

        $remaining = (new OtpService())->cooldownRemaining($email);

        return view('auth/verify_otp', [
            'title'            => 'OTP Verification',
            'email'            => $email,
            'maskedEmail'      => EmailAddress::mask($email),
            'resendRemaining'  => $remaining,
            'showSentBanner'   => session()->getFlashdata('otp_sent') === true,
        ]);
    }

    public function verifyOtp()
    {
        $email = (string) session()->get('otp_email');
        if ($email === '') {
            return redirect()->to('/sign-in');
        }

        $otp    = preg_replace('/\D+/', '', (string) $this->request->getPost('otp')) ?? '';
        $result = (new OtpService())->verify($email, $otp);

        if (! ($result['ok'] ?? false)) {
            return $this->authError($result['message'] ?? OtpService::MSG_INCORRECT);
        }

        $sessions = new AuthSessionService();
        $user     = $sessions->identifyOrCreate($email);
        if ($user === null) {
            return $this->authError('This account is not active.');
        }

        $sessions->establish($user, regenerate: true);
        (new PersistentLoginService())->issueToken((int) $user['id']);
        session()->remove(['otp_email', 'otp_sent_at']);

        return redirect()->to($sessions->authenticatedDestination())->withCookies();
    }

    public function resendOtp()
    {
        $email = (string) session()->get('otp_email');
        if ($email === '') {
            return redirect()->to('/sign-in');
        }

        $result = (new OtpService())->resend($email);
        if (! ($result['ok'] ?? false)) {
            return $this->authError($result['message'] ?? OtpService::MSG_SEND_FAIL);
        }

        session()->set('otp_sent_at', time());

        return redirect()->to('/auth/verify-otp')->with('otp_sent', true);
    }

    public function logout()
    {
        (new PersistentLoginService())->revokeCurrent();
        session()->destroy();

        return redirect()->to('/sign-in')
            ->withCookies()
            ->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
            ->setHeader('Pragma', 'no-cache');
    }

    private function authError(string $message, ?string $email = null)
    {
        if ($this->request->isAJAX()) {
            return $this->response->setJSON([
                'ok'    => false,
                'error' => $message,
            ]);
        }

        $redirect = redirect()->back()->with('error', $message);
        if ($email !== null) {
            $redirect->withInput();
        }

        return $redirect;
    }
}
