<?php

namespace App\Controllers;

use App\Models\ProfileModel;
use App\Models\MemberOtpModel;

/**
 * MemberAuthController — mobile OTP login for profile owners.
 *
 * Flow:
 *  1. GET  /member/login      → show mobile + CAPTCHA form
 *  2. POST /member/send-otp   → validate mobile & CAPTCHA, generate DB OTP
 *  3. GET  /member/verify     → show 6-digit OTP form
 *  4. POST /member/verify     → verify OTP against DB, redirect to profile
 *  5. GET  /member/captcha    → serve CAPTCHA image (PNG)
 *  6. POST /member/resend-otp → regenerate OTP in DB
 *  7. GET  /member/logout     → clear member session
 */
class MemberAuthController extends BaseController
{
    private ProfileModel   $profileModel;
    private MemberOtpModel $otpModel;

    private const OTP_EXPIRY_SECONDS = 300;  // 5 minutes
    private const MAX_OTP_ATTEMPTS   = 5;

    public function __construct()
    {
        $this->profileModel = new ProfileModel();
        $this->otpModel     = new MemberOtpModel();
    }

    // ----------------------------------------------------------------
    // GET /member/login
    // ----------------------------------------------------------------
    public function loginForm()
    {
        if (session()->get('member_profile_id')) {
            return redirect()->to(site_url('profile/' . session()->get('member_slug')));
        }

        return view('member/login');
    }

    // ----------------------------------------------------------------
    // POST /member/send-otp
    // ----------------------------------------------------------------
    public function sendOtp()
    {
        $countryCode = trim($this->request->getPost('country_code') ?? '+91');
        $mobile      = preg_replace('/\D/', '', trim($this->request->getPost('mobile') ?? ''));
        $captcha     = strtoupper(trim($this->request->getPost('captcha') ?? ''));

        // ── Validate mobile ──
        if (empty($mobile) || strlen($mobile) < 7 || strlen($mobile) > 15) {
            return redirect()->to(site_url('member/login'))
                             ->withInput()
                             ->with('error_mobile', 'Please enter a valid mobile number.');
        }

        // ── Validate CAPTCHA ──
        $expected = strtoupper(session()->get('captcha_code') ?? '');
        if (empty($captcha) || $captcha !== $expected) {
            session()->remove('captcha_code');
            return redirect()->to(site_url('member/login'))
                             ->withInput()
                             ->with('error_captcha', 'Incorrect CAPTCHA. Please try again.');
        }
        session()->remove('captcha_code'); // consume it

        // ── Look up profile by mobile ──
        $profile = $this->findProfileByMobile($countryCode, $mobile);
        if (! $profile) {
            return redirect()->to(site_url('member/login'))
                             ->withInput()
                             ->with('error_mobile', 'Mobile number not found. Please contact your administrator.');
        }

        // ── Generate OTP and store in DB ──
        $otp = $this->otpModel->createOtp((int) $profile['id'], self::OTP_EXPIRY_SECONDS);

        // TODO: Send $otp via SMS gateway
        // SmsService::send($countryCode . $mobile, "Your OTP is: {$otp}. Valid for 5 minutes.");

        // ── Store pending session (no OTP here — it lives in DB) ──
        session()->set([
            'member_pending_mobile'       => $mobile,
            'member_pending_country_code' => $countryCode,
            'member_pending_profile_id'   => $profile['id'],
            'member_pending_slug'         => $profile['slug'],
            'member_pending_name'         => $profile['name'],
        ]);

        return redirect()->to(site_url('member/verify'));
    }

    // ----------------------------------------------------------------
    // GET /member/verify
    // ----------------------------------------------------------------
    public function otpForm()
    {
        if (! session()->get('member_pending_profile_id')) {
            return redirect()->to(site_url('member/login'));
        }

        $cc     = session()->get('member_pending_country_code') ?? '';
        $mobile = session()->get('member_pending_mobile') ?? '';
        $masked = $cc . ' XXXXXX' . substr($mobile, -4);

        return view('member/otp', ['maskedMobile' => $masked]);
    }

    // ----------------------------------------------------------------
    // POST /member/verify
    // ----------------------------------------------------------------
    public function verifyOtp()
    {
        if (! session()->get('member_pending_profile_id')) {
            return redirect()->to(site_url('member/login'));
        }

        $profileId = (int) session()->get('member_pending_profile_id');

        // Collect 6 digit boxes → otp_1 … otp_6
        $entered = '';
        for ($i = 1; $i <= 6; $i++) {
            $entered .= preg_replace('/\D/', '', $this->request->getPost('otp_' . $i) ?? '');
        }

        // ── Fetch active OTP from DB ──
        $otpRow = $this->otpModel->getActiveOtp($profileId);

        if (! $otpRow) {
            // No active OTP — expired or never generated
            $this->clearPendingSession();
            return redirect()->to(site_url('member/login'))
                             ->with('error', 'OTP has expired. Please request a new one.');
        }

        // ── Check max attempts ──
        if ((int) $otpRow['attempts'] >= self::MAX_OTP_ATTEMPTS) {
            $this->otpModel->clearForProfile($profileId);
            $this->clearPendingSession();
            return redirect()->to(site_url('member/login'))
                             ->with('error', 'Too many failed attempts. Please start over.');
        }

        // ── Verify OTP ──
        if ($entered !== $otpRow['otp_code']) {
            $this->otpModel->incrementAttempts((int) $otpRow['id']);
            $remaining = self::MAX_OTP_ATTEMPTS - (int) $otpRow['attempts'] - 1;
            return redirect()->to(site_url('member/verify'))
                             ->with('error_otp', 'Invalid OTP. ' . $remaining . ' attempt' . ($remaining === 1 ? '' : 's') . ' remaining.');
        }

        // ── SUCCESS — mark OTP as used ──
        $this->otpModel->markUsed((int) $otpRow['id']);

        // ── Promote to logged-in session ──
        session()->set([
            'member_profile_id' => session()->get('member_pending_profile_id'),
            'member_slug'       => session()->get('member_pending_slug'),
            'member_name'       => session()->get('member_pending_name'),
        ]);
        $slug = session()->get('member_slug');
        $this->clearPendingSession();

        return redirect()->to(site_url('member/profile/edit'));
    }

    // ----------------------------------------------------------------
    // POST /member/resend-otp
    // ----------------------------------------------------------------
    public function resendOtp()
    {
        if (! session()->get('member_pending_profile_id')) {
            return redirect()->to(site_url('member/login'));
        }

        $profileId = (int) session()->get('member_pending_profile_id');

        // Generate a fresh OTP in DB (also purges the old one)
        $otp = $this->otpModel->createOtp($profileId, self::OTP_EXPIRY_SECONDS);

        // TODO: Send $otp via SMS gateway
        // SmsService::send(..., "Your new OTP is: {$otp}");

        return redirect()->to(site_url('member/verify'))
                         ->with('success_otp', 'OTP resent successfully.');
    }

    // ----------------------------------------------------------------
    // GET /member/captcha  — returns a PNG CAPTCHA image
    // ----------------------------------------------------------------
    public function captchaImage()
    {
        // 5-char alphanumeric (no 0/O/1/I confusion)
        $chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
        $code  = '';
        for ($i = 0; $i < 5; $i++) {
            $code .= $chars[random_int(0, strlen($chars) - 1)];
        }
        session()->set('captcha_code', $code);

        $w = 150; $h = 48;
        $img = imagecreatetruecolor($w, $h);

        // Background
        $bg = imagecolorallocate($img, 248, 249, 252);
        imagefilledrectangle($img, 0, 0, $w, $h, $bg);

        // Noise lines
        for ($i = 0; $i < 5; $i++) {
            $lc = imagecolorallocate($img, random_int(180, 220), random_int(180, 220), random_int(180, 220));
            imageline($img, random_int(0,$w), random_int(0,$h), random_int(0,$w), random_int(0,$h), $lc);
        }
        // Noise dots
        for ($i = 0; $i < 80; $i++) {
            $dc = imagecolorallocate($img, random_int(160, 230), random_int(160, 230), random_int(160, 230));
            imagesetpixel($img, random_int(0,$w), random_int(0,$h), $dc);
        }

        // Character colours
        $palette = [
            imagecolorallocate($img, 220,  80,   0),
            imagecolorallocate($img,   0, 110, 200),
            imagecolorallocate($img,  20, 140,  60),
            imagecolorallocate($img, 160,  20, 160),
            imagecolorallocate($img, 180,  30,  30),
        ];

        // Try TTF fonts (Windows + Linux paths)
        $fontCandidates = [
            'C:/Windows/Fonts/arialbd.ttf',
            'C:/Windows/Fonts/arial.ttf',
            '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf',
            '/usr/share/fonts/dejavu/DejaVuSans-Bold.ttf',
            FCPATH . 'assets/fonts/DejaVuSans-Bold.ttf',
        ];
        $font = null;
        foreach ($fontCandidates as $f) {
            if (file_exists($f)) { $font = $f; break; }
        }

        $x = 12;
        for ($i = 0; $i < strlen($code); $i++) {
            $color = $palette[$i % count($palette)];
            if ($font) {
                $size  = random_int(16, 20);
                $angle = random_int(-18, 18);
                $y     = random_int(32, 38);
                imagettftext($img, $size, $angle, $x, $y, $color, $font, $code[$i]);
                $x += 26;
            } else {
                $y = random_int(8, 16);
                imagestring($img, 5, $x, $y, $code[$i], $color);
                $x += 26;
            }
        }

        header('Content-Type: image/png');
        header('Cache-Control: no-store, no-cache, must-revalidate');
        header('Pragma: no-cache');
        imagepng($img);
        imagedestroy($img);
        exit;
    }

    // ----------------------------------------------------------------
    // GET /member/logout
    // ----------------------------------------------------------------
    public function logout()
    {
        session()->remove(['member_profile_id', 'member_slug', 'member_name']);
        return redirect()->to(site_url('member/login'));
    }

    // ----------------------------------------------------------------
    // Private helpers
    // ----------------------------------------------------------------

    /**
     * Find an active profile matching country_code + mobile.
     * Uses PHP-side comparison because mobile is AES-encrypted at rest.
     */
    private function findProfileByMobile(string $countryCode, string $mobile): ?array
    {
        $profiles = $this->profileModel
            ->select('id, name, slug, mobile, mobile_country_code')
            ->where('is_active', 1)
            ->where('deleted_at IS NULL')
            ->findAll();

        foreach ($profiles as $p) {
            $storedMobile = preg_replace('/\D/', '', $p['mobile'] ?? '');
            $storedCC     = trim($p['mobile_country_code'] ?? '');

            if ($storedMobile === $mobile && $storedCC === $countryCode) {
                return $p;
            }
        }
        return null;
    }

    /** Remove all pending OTP session keys. */
    private function clearPendingSession(): void
    {
        session()->remove([
            'member_pending_mobile',
            'member_pending_country_code',
            'member_pending_profile_id',
            'member_pending_slug',
            'member_pending_name',
        ]);
    }
}
