<?php
// auth_functions.php

require_once __DIR__ . '/config.php';
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/sms_helper.php'; // SMS helper for Twilio/local SMS gateway

/**
 * Generate and store a secure OTP (hashed in DB).
 */
function generateOTP($memberId, $purpose = 'login', $expiryMinutes = 15) {
    global $pdo;

    // Clean expired + old OTPs for this member & purpose
    $stmt = $pdo->prepare("
        DELETE FROM member_otps 
        WHERE (expires_at < NOW()) 
           OR (member_id = ? AND purpose = ? AND used = FALSE)
    ");
    $stmt->execute([$memberId, $purpose]);

    // Generate 6-digit numeric OTP
    $otp = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
    $otpHash = password_hash($otp, PASSWORD_BCRYPT);

    $expiresAt = date('Y-m-d H:i:s', strtotime("+$expiryMinutes minutes"));

    $stmt = $pdo->prepare("
        INSERT INTO member_otps (member_id, token, purpose, expires_at)
        VALUES (?, ?, ?, ?)
    ");
    $stmt->execute([$memberId, $otpHash, $purpose, $expiresAt]);

    return $otp; // return plain OTP for delivery
}

/**
 * Verify OTP against stored hash.
 */
function verifyOTP($memberId, $otp, $purpose = 'login') {
    global $pdo;

    $stmt = $pdo->prepare("
        SELECT id, token, expires_at, used 
        FROM member_otps 
        WHERE member_id = ? 
          AND purpose = ? 
        ORDER BY created_at DESC 
        LIMIT 1
    ");
    $stmt->execute([$memberId, $purpose]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$row) {
        return false;
    }

    if ($row['used'] || strtotime($row['expires_at']) < time()) {
        return false;
    }

    if (!password_verify($otp, $row['token'])) {
        return false;
    }

    // Mark OTP as used
    $pdo->prepare("UPDATE member_otps SET used = TRUE WHERE id = ?")
        ->execute([$row['id']]);

    return true;
}

/**
 * Load SMTP configuration from JSON file.
 */
function loadSmtpConfig() {
    $jsonFilePath = __DIR__ . '/smtp_settings_data.json';

    if (!file_exists($jsonFilePath)) {
        error_log("SMTP config file not found at: $jsonFilePath");
        throw new Exception('SMTP configuration not available. Please contact administrator.');
    }

    $permissions = substr(sprintf('%o', fileperms($jsonFilePath)), -3);
    if ($permissions !== '600') {
        error_log("Insecure SMTP config permissions: $permissions (should be 600)");
        @chmod($jsonFilePath, 0600);
    }

    $json = file_get_contents($jsonFilePath);
    if ($json === false) {
        throw new Exception('Failed to read SMTP configuration.');
    }

    $config = json_decode($json, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new Exception('Invalid SMTP configuration format.');
    }

    return [
        'host'        => $config['smtp_host'] ?? '',
        'username'    => $config['smtp_username'] ?? '',
        'password'    => $config['smtp_password'] ?? '',
        'port'        => $config['smtp_port'] ?? 587,
        'encryption'  => $config['smtp_encryption'] ?? 'tls',
        'from_address'=> $config['from_address'] ?? '',
        'from_name'   => $config['from_name'] ?? ''
    ];
}

/**
 * Send OTP via email.
 */
function sendOTPEmail($email, $otp) {
    try {
        $smtpConfig = loadSmtpConfig();

        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new Exception("Invalid email address: $email");
        }

        $mail = new PHPMailer\PHPMailer\PHPMailer(true);

        $mail->SMTPDebug = 0;
        $mail->Debugoutput = function($str) { error_log("PHPMailer: $str"); };

        $mail->isSMTP();
        $mail->Host       = $smtpConfig['host'];
        $mail->SMTPAuth   = true;
        $mail->Username   = $smtpConfig['username'];
        $mail->Password   = $smtpConfig['password'];
        $mail->SMTPSecure = $smtpConfig['encryption'];
        $mail->Port       = $smtpConfig['port'];

        $mail->setFrom($smtpConfig['from_address'], $smtpConfig['from_name']);
        $mail->addAddress($email);

        $mail->isHTML(true);
        $mail->Subject = 'Your One-Time Password (OTP)';

        $currentTime = date('Y-m-d H:i:s');
        $ipAddress   = $_SERVER['REMOTE_ADDR'] ?? 'unknown';

        $mail->Body = "
            <h2>Your One-Time Password</h2>
            <p>Your verification code is: <strong>$otp</strong></p>
            <p>This code will expire in 15 minutes.</p>
            <hr>
            <small>Request IP: $ipAddress<br>Time: $currentTime</small>
        ";
        $mail->AltBody = "Your OTP code: $otp (expires in 15 minutes).\nIP: $ipAddress\nTime: $currentTime";

        $mail->send();
        return true;
    } catch (Exception $e) {
        error_log("OTP Email Failed: " . $e->getMessage());
        return false;
    }
}

/**
 * Send OTP via SMS.
 */
function sendOTPSms(PDO $pdo, string $phoneNumber, string $otp): bool {
    $message = "Your verification code is $otp. It will expire in 15 minutes.";
    $result = sendSms($pdo, $phoneNumber, $message);

    return $result['type'] === 'success';
}

/**
 * Security logging (login attempts, OTP events, etc.)
 */
function logSecurityEvent($memberId, $action, $details = null) {
    global $pdo;

    try {
        $stmt = $pdo->prepare("
            INSERT INTO security_logs (member_id, action, ip_address, user_agent, details) 
            VALUES (?, ?, ?, ?, ?)
        ");

        $details = is_array($details) ? json_encode($details) : $details;

        $stmt->execute([
            $memberId,
            $action,
            $_SERVER['REMOTE_ADDR'] ?? null,
            $_SERVER['HTTP_USER_AGENT'] ?? null,
            $details
        ]);
        return true;
    } catch (PDOException $e) {
        error_log("Failed to log security event: " . $e->getMessage());
        return false;
    }
}

/**
 * Send OTP using member's communication preference.
 */
function sendOTPByPreference($member, $purpose = 'login') {
    global $pdo;

    $memberId = $member['member_id'] ?? $member['id'] ?? null;
    if (!$memberId) {
        logSecurityEvent(null, 'otp_failed', ["reason" => "missing_member_id"]);
        return false;
    }

    $otp = generateOTP($memberId, $purpose);
    $pref = strtolower($member['communication_preference'] ?? 'email');

    $sent = false;
    $channelUsed = null;

    if (($pref === 'email' || $pref === 'both') && !empty($member['email'])) {
        $sent = sendOTPEmail($member['email'], $otp);
        if ($sent) $channelUsed = 'email';
    }

    if ((!$sent && $pref === 'sms') || ($pref === 'both' && !$sent)) {
        if (!empty($member['phone_number'])) {
            $sent = sendOTPSms($pdo, $member['phone_number'], $otp);
            if ($sent) $channelUsed = 'sms';
        }
    }

    logSecurityEvent(
        $memberId,
        $sent ? "otp_sent" : "otp_failed",
        ["purpose" => $purpose, "pref" => $pref, "channel" => $channelUsed]
    );

    return $sent;
}
