<?php
// ═══════════════════════════════════════════════════════════
//  FICTION IGNITION — api/auth/index.php
//  Routes: POST /api/auth/?action=register
//          POST /api/auth/?action=login
//          POST /api/auth/?action=logout
//          GET  /api/auth/?action=verify&token=xxx
//          GET  /api/auth/?action=me
//          POST /api/auth/?action=forgot-password
//          POST /api/auth/?action=reset-password
// ═══════════════════════════════════════════════════════════

declare(strict_types=1);

// Config MUST come first — it sets up the global error handler
require_once __DIR__ . '/../lib/config.php';

// Set JSON headers immediately after config loads
fi_json_headers();

// Mailer is loaded lazily — only when we actually need to send email.
// This way a missing vendor/autoload.php won't crash the whole endpoint.
function fi_load_mailer(): void {
    static $loaded = false;
    if ($loaded) return;
    require_once __DIR__ . '/../lib/mailer.php';
    $loaded = true;
}

$method = $_SERVER['REQUEST_METHOD'];
$action = $_GET['action'] ?? '';
$input  = json_decode(file_get_contents('php://input'), true) ?? [];

// ── Router ─────────────────────────────────────────────────
match (true) {
    $method === 'POST' && $action === 'register'        => handle_register($input),
    $method === 'POST' && $action === 'login'           => handle_login($input),
    $method === 'POST' && $action === 'logout'          => handle_logout(),
    $method === 'GET'  && $action === 'verify'          => handle_verify(),
    $method === 'GET'  && $action === 'me'              => handle_me(),
    $method === 'POST' && $action === 'forgot-password' => handle_forgot($input),
    $method === 'POST' && $action === 'reset-password'  => handle_reset($input),
    default => fi_error('Unknown action: ' . htmlspecialchars($action), 404),
};

// ── Register ───────────────────────────────────────────────
function handle_register(array $in): never {
    $name     = trim($in['name']     ?? '');
    $email    = strtolower(trim($in['email']    ?? ''));
    $password = $in['password'] ?? '';

    if (!$name)                      fi_error('Name is required.');
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) fi_error('Enter a valid email address.');
    if (strlen($password) < 6)       fi_error('Password must be at least 6 characters.');
    if (strlen($name) > 120)         fi_error('Name is too long.');

    $db = fi_db();

    // Duplicate email check
    $stmt = $db->prepare('SELECT id FROM users WHERE email = ? LIMIT 1');
    $stmt->execute([$email]);
    if ($stmt->fetch()) fi_error('An account with that email already exists.');

    // Create user
    $userId       = fi_uuid();
    $passwordHash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);

    $db->prepare('
        INSERT INTO users (id, name, email, password_hash, tier, email_verified, isAdmin)
        VALUES (?, ?, ?, ?, \'free\', 0, 0)
    ')->execute([$userId, $name, $email, $passwordHash]);

    // Generate email verification token
    $token     = bin2hex(random_bytes(32));
    $expiresAt = date('Y-m-d H:i:s', strtotime('+24 hours'));

    $db->prepare('INSERT INTO email_tokens (token, user_id, expires_at) VALUES (?,?,?)')
       ->execute([$token, $userId, $expiresAt]);

    // Send verification email (non-fatal if mailer not configured)
    $verifyUrl = rtrim(env('APP_URL', ''), '/') . '/api/auth/?action=verify&token=' . $token;
    try {
        fi_load_mailer();
        $html = fi_email_verify_template($name, $verifyUrl);
        fi_send_email($email, $name, 'Verify your Fiction Ignition account', $html);
    } catch (Throwable $e) {
        error_log('Fiction Ignition: Verification email failed: ' . $e->getMessage());
        // Still succeed — user can request resend later
    }

    fi_ok([
        'message'    => 'Account created! Check your email to verify your address before signing in.',
        'user_id'    => $userId,
        'verify_url' => env('APP_ENV') === 'development' ? $verifyUrl : null, // only expose in dev
    ]);
}

// ── Login ──────────────────────────────────────────────────
function handle_login(array $in): never {
    $email    = strtolower(trim($in['email']    ?? ''));
    $password = $in['password'] ?? '';

    if (!$email || !$password) fi_error('Please fill in all fields.');

    $db   = fi_db();
    $stmt = $db->prepare('SELECT * FROM users WHERE email = ? LIMIT 1');
    $stmt->execute([$email]);
    $user = $stmt->fetch();

    if (!$user || !password_verify($password, $user['password_hash'])) {
        fi_error('Incorrect email or password.');
    }

    if (!$user['email_verified']) {
        fi_error('Please verify your email address before signing in. Check your inbox for the verification link.');
    }

    // Create session
    $sessionId = bin2hex(random_bytes(32));
    $days      = (int) env('SESSION_LIFETIME_DAYS', '30');
    $expiresAt = date('Y-m-d H:i:s', strtotime("+{$days} days"));

    $db->prepare('INSERT INTO sessions (id, user_id, expires_at) VALUES (?,?,?)')
       ->execute([$sessionId, $user['id'], $expiresAt]);

    // Set session cookie
    $secure = env('SESSION_COOKIE_SECURE', 'true') === 'true';
    setcookie(
        env('SESSION_COOKIE_NAME', 'fi_session'),
        $sessionId,
        [
            'expires'  => strtotime("+{$days} days"),
            'path'     => '/',
            'httponly' => true,
            'secure'   => $secure,
            'samesite' => 'Strict',
        ]
    );

    fi_ok([
        'user' => [
            'id'      => $user['id'],
            'name'    => $user['name'],
            'email'   => $user['email'],
            'tier'    => $user['tier'],
            'isAdmin' => (bool)($user['isAdmin'] ?? false),
        ],
    ]);
}

// ── Logout ─────────────────────────────────────────────────
function handle_logout(): never {
    $cookieName = env('SESSION_COOKIE_NAME', 'fi_session');
    $token      = $_COOKIE[$cookieName] ?? null;
    if ($token) {
        fi_db()->prepare('DELETE FROM sessions WHERE id = ?')->execute([$token]);
    }
    setcookie($cookieName, '', ['expires' => time() - 3600, 'path' => '/', 'httponly' => true, 'secure' => true, 'samesite' => 'Strict']);
    fi_ok(['message' => 'Signed out.']);
}

// ── Verify email ───────────────────────────────────────────
function handle_verify(): never {
    $token = $_GET['token'] ?? '';
    if (!$token) fi_error('Invalid verification link.');

    $db   = fi_db();
    $stmt = $db->prepare('SELECT * FROM email_tokens WHERE token = ? AND used = 0 AND expires_at > NOW() LIMIT 1');
    $stmt->execute([$token]);
    $row = $stmt->fetch();

    if (!$row) fi_error('Verification link is invalid or has expired. Please register again.');

    // Mark verified
    $db->prepare('UPDATE users SET email_verified = 1 WHERE id = ?')->execute([$row['user_id']]);
    $db->prepare('UPDATE email_tokens SET used = 1 WHERE token = ?')->execute([$token]);

    // Send welcome email (non-fatal)
    try {
        fi_load_mailer();
        $userStmt = $db->prepare('SELECT name, email FROM users WHERE id = ? LIMIT 1');
        $userStmt->execute([$row['user_id']]);
        $user = $userStmt->fetch();
        if ($user) {
            $html = fi_email_welcome_template($user['name']);
            fi_send_email($user['email'], $user['name'], 'Welcome to Fiction Ignition! 🔥', $html);
        }
    } catch (Throwable $e) {
        error_log('Fiction Ignition: Welcome email failed: ' . $e->getMessage());
    }

    // Redirect to app with success flag
    $appUrl = rtrim(env('APP_URL', ''), '/');
    header('Location: ' . $appUrl . '/app.html?verified=1');
    exit;
}

// ── Me (session check) ─────────────────────────────────────
function handle_me(): never {
    $session = fi_get_session();
    if (!$session) fi_error('Not authenticated.', 401);

    $used = fi_prompts_used_today($session['id']);
    $tier = $session['tier'];
    $info = TIERS[$tier] ?? TIERS['free'];
    $left = $info['daily_limit'] === PHP_INT_MAX ? null : max(0, $info['daily_limit'] - $used);

    fi_ok([
        'user' => [
            'id'      => $session['id'],
            'name'    => $session['name'],
            'email'   => $session['email'],
            'tier'    => $tier,
            'isAdmin' => (bool)($session['isAdmin'] ?? false),
        ],
        'usage' => [
            'used_today'   => $used,
            'daily_limit'  => $info['daily_limit'] === PHP_INT_MAX ? null : $info['daily_limit'],
            'prompts_left' => $left,
        ],
        'features' => [
            'ad_free'      => $info['ad_free'],
            'history'      => $info['history'],
            'export'       => $info['export'],
            'custom_genre' => $info['custom_genre'],
            'advanced_ai'  => $info['advanced_ai'],
        ],
    ]);
}

// ── Forgot password ────────────────────────────────────────
function handle_forgot(array $in): never {
    $email = strtolower(trim($in['email'] ?? ''));
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) fi_error('Enter a valid email address.');

    $db   = fi_db();
    $stmt = $db->prepare('SELECT id, name FROM users WHERE email = ? LIMIT 1');
    $stmt->execute([$email]);
    $user = $stmt->fetch();

    if ($user) {
        $token     = bin2hex(random_bytes(32));
        $expiresAt = date('Y-m-d H:i:s', strtotime('+1 hour'));
        $db->prepare('INSERT INTO reset_tokens (token, user_id, expires_at) VALUES (?,?,?)')->execute([$token, $user['id'], $expiresAt]);

        $resetUrl = rtrim(env('APP_URL', ''), '/') . '/reset-password.html?token=' . $token;
        $html = '<h2>Reset your password</h2><p>Hi ' . htmlspecialchars($user['name']) . ', click below to reset your Fiction Ignition password. This link expires in 1 hour.</p>'
              . '<p><a href="' . $resetUrl . '" style="background:#e8610a;color:#fff;padding:12px 24px;border-radius:6px;text-decoration:none;font-weight:600">Reset Password</a></p>'
              . '<p style="font-size:.85rem;color:#888">If you didn\'t request this, ignore this email.</p>';
        try {
            fi_load_mailer();
            fi_send_email($email, $user['name'], 'Reset your Fiction Ignition password', $html);
        } catch (Throwable $e) {
            error_log('Fiction Ignition: Reset email failed: ' . $e->getMessage());
        }
    }

    fi_ok(['message' => 'If that email exists, a reset link has been sent.']);
}

// ── Reset password ─────────────────────────────────────────
function handle_reset(array $in): never {
    $token    = $in['token']    ?? '';
    $password = $in['password'] ?? '';

    if (!$token)               fi_error('Invalid reset link.');
    if (strlen($password) < 6) fi_error('Password must be at least 6 characters.');

    $db   = fi_db();
    $stmt = $db->prepare('SELECT * FROM reset_tokens WHERE token = ? AND used = 0 AND expires_at > NOW() LIMIT 1');
    $stmt->execute([$token]);
    $row = $stmt->fetch();
    if (!$row) fi_error('Reset link is invalid or has expired.');

    $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
    $db->prepare('UPDATE users SET password_hash = ? WHERE id = ?')->execute([$hash, $row['user_id']]);
    $db->prepare('UPDATE reset_tokens SET used = 1 WHERE token = ?')->execute([$token]);
    $db->prepare('DELETE FROM sessions WHERE user_id = ?')->execute([$row['user_id']]);

    fi_ok(['message' => 'Password updated. Please sign in.']);
}
