<?php
require_once '../config.php';
require_once '../middleware.php';

// Generate a random 4-character alphanumeric string
function generateRandomAlphanumeric() {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $randomString = '';
    for ($i = 0; $i < 4; $i++) {
        $randomString .= $characters[rand(0, strlen($characters) - 1)];
    }
    return $randomString;
}

// Generate a unique refercode
function generateRefercode($email, $conn) {
    $emailPrefix = strtolower(substr($email, 0, 4));
    $maxAttempts = 10;
    $attempt = 0;

    while ($attempt < $maxAttempts) {
        $randomPart = generateRandomAlphanumeric();
        $refercode = $emailPrefix . $randomPart;

        $stmt = $conn->prepare("SELECT id FROM users WHERE refercode = ?");
        $stmt->bind_param("s", $refercode);
        $stmt->execute();
        $result = $stmt->get_result();

        if ($result->num_rows === 0) {
            $stmt->close();
            return $refercode;
        }

        $stmt->close();
        $attempt++;
    }

    sendResponse(500, 'Unable to generate a unique referral code after multiple attempts');
}

// Mask email for error messages (e.g., sachxxxxrwr@gmail.com)
function maskEmail($email) {
    $parts = explode('@', $email);
    if (count($parts) !== 2) {
        return $email; // Invalid email format, return as-is
    }

    $localPart = $parts[0];
    $domainPart = $parts[1];

    // Mask the local part (e.g., sachin -> sachxxxx)
    $localLength = strlen($localPart);
    if ($localLength <= 4) {
        return $localPart . 'xxxx@' . $domainPart;
    }
    $maskedLocal = substr($localPart, 0, 4) . str_repeat('x', $localLength - 4);
    
    // Mask the domain part (e.g., gmail -> rwr)
    $domainParts = explode('.', $domainPart);
    $mainDomain = $domainParts[0];
    $domainLength = strlen($mainDomain);
    $maskedDomain = $domainLength > 3 ? 'rwr' : $mainDomain;
    $maskedDomain .= '.' . (isset($domainParts[1]) ? $domainParts[1] : '');

    return $maskedLocal . '@' . $maskedDomain;
}

// Check if user can claim daily checkin
function checkDailyCheckinStatus($user_id, $conn) {
    $today = date('Y-m-d');
    $can_claim = true;
    
    // Check if daily_checkins table exists
    $table_exists = false;
    try {
        $stmt = $conn->prepare("SHOW TABLES LIKE 'daily_checkins'");
        $stmt->execute();
        $result = $stmt->get_result();
        $table_exists = $result->num_rows > 0;
        $stmt->close();
    } catch (Exception $e) {
        $table_exists = false;
    }
    
    if ($table_exists) {
        try {
            $stmt = $conn->prepare("SELECT claimed_at FROM daily_checkins WHERE user_id = ? AND DATE(claimed_at) = ? ORDER BY claimed_at DESC LIMIT 1");
            $stmt->bind_param("is", $user_id, $today);
            $stmt->execute();
            $result = $stmt->get_result();
            $can_claim = $result->num_rows === 0;
            $stmt->close();
        } catch (Exception $e) {
            $can_claim = true;
        }
    }
    
    return $can_claim;
}

### API Blueprint: /user/account
# POST /user/account
# Description: Handles user login and signup with a "one device, one account" policy.
# Headers:
#   - Device-ID: <device_id> (required)
# Request Body:
#   - email: string (required)
#   - device_id: string (required)
# Response:
#   - 200: Success (Login or Signup)
#     {
#       "status": 200,
#       "message": "Login successful",
#       "data": {
#         "user_id": 1,
#         "email": "user@example.com",
#         "refercode": "user1234"
#       },
#       "session_token": "strong_session_token_64_chars"
#     }
#   - 400: Missing or empty field, Device already used, Email already registered
#   - 429: Too many requests
#   - 500: Database connection failed

$device_id = $_SERVER['HTTP_DEVICE_ID'] ?? '';
if (empty($device_id)) {
    sendResponse(400, 'Device-ID header is required');
}

$method = $_SERVER['REQUEST_METHOD'];
if ($method === 'POST') {
    // Get the encrypted payload
    $encrypted_payload = file_get_contents('php://input');
    if (empty($encrypted_payload)) {
        sendResponse(400, 'Empty request body');
    }

    // Decrypt the payload
    $data = decryptRequestPayload($encrypted_payload);
    if (!$data) {
        sendResponse(400, 'Invalid request body');
    }

    if ($data['device_id'] !== $device_id) {
        sendResponse(400, 'Device-ID in header and body must match');
    }

    $conn = getDbConnection();
    $email = $data['email'];
    $device_id = $data['device_id'];

    rateLimit(0); // Rate limit for unauthenticated requests

    // Check if device_id exists
    $stmt = $conn->prepare("SELECT id, email, refercode, coins FROM users WHERE device_id = ?");
    $stmt->bind_param("s", $device_id);
    $stmt->execute();
    $device_result = $stmt->get_result();

    // Check if email exists
    $stmt = $conn->prepare("SELECT id, device_id FROM users WHERE email = ?");
    $stmt->bind_param("s", $email);
    $stmt->execute();
    $email_result = $stmt->get_result();

    $device_exists = $device_result->num_rows > 0;
    $email_exists = $email_result->num_rows > 0;

    if ($device_exists && $email_exists) {
        // Both device_id and email exist, check if they are associated with the same account
        $device_row = $device_result->fetch_assoc();
        $email_row = $email_result->fetch_assoc();

        if ($device_row['id'] === $email_row['id']) {
            // Same account, allow login
            $user_id = $device_row['id'];
            rateLimit($user_id);

            // Generate new session token for login
            $session_token = bin2hex(random_bytes(32));
            $expires_at = date('Y-m-d H:i:s', strtotime('+30 days'));

            $stmt = $conn->prepare("INSERT INTO session_tokens (user_id, device_id, session_token, expires_at) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE session_token = ?, created_at = NOW(), expires_at = ?");
            $stmt->bind_param("isssss", $user_id, $device_id, $session_token, $expires_at, $session_token, $expires_at);
            $stmt->execute();

            // Check daily checkin status
            $can_claim = checkDailyCheckinStatus($user_id, $conn);

            sendResponse(200, 'Login successful', [
                'user_id' => $user_id,
                'email' => $device_row['email'],
                'refercode' => $device_row['refercode'],
                'coins' => $device_row['coins'],
                'can_claim' => $can_claim
            ], $session_token);
        } else {
            // Device and email belong to different accounts
            $masked_email = maskEmail($device_row['email']);
            sendResponse(400, "This device is already used in another account: $masked_email");
        }
    } elseif ($device_exists) {
        // Device exists, but email does not match
        $device_row = $device_result->fetch_assoc();
        $masked_email = maskEmail($device_row['email']);
        sendResponse(400, "This device is already used in another account: $masked_email");
    } elseif ($email_exists) {
        // Email exists, but device does not match
        sendResponse(400, 'This email ID is already registered with another device');
    } else {
        // Neither device_id nor email exists, proceed with signup
        $refercode = generateRefercode($email, $conn);

        // Handle optional refercode from request
        $referred_by = null;
        if (isset($data['refercode']) && !empty($data['refercode'])) {
            $input_refercode = $data['refercode'];
            // Validate refercode format (alphanumeric, 8 characters)
            if (preg_match('/^[a-zA-Z0-9]{8}$/', $input_refercode)) {
                // Check if refercode exists and is not the same as the one being generated
                $stmt_ref = $conn->prepare("SELECT id FROM users WHERE refercode = ?");
                $stmt_ref->bind_param("s", $input_refercode);
                $stmt_ref->execute();
                $result_ref = $stmt_ref->get_result();
                if ($result_ref->num_rows > 0) {
                    $ref_row = $result_ref->fetch_assoc();
                    $referred_by = $ref_row['id'];
                }
                $stmt_ref->close();
            }
        }

        // Register new user
        if ($referred_by) {
            $stmt = $conn->prepare("INSERT INTO users (email, device_id, refercode, referred_by) VALUES (?, ?, ?, ?)");
            $stmt->bind_param("sssi", $email, $device_id, $refercode, $referred_by);
        } else {
            $stmt = $conn->prepare("INSERT INTO users (email, device_id, refercode) VALUES (?, ?, ?)");
            $stmt->bind_param("sss", $email, $device_id, $refercode);
        }
        if ($stmt->execute()) {
            $user_id = $stmt->insert_id;
            rateLimit($user_id);

            // Fetch new user's coins
            $stmt_user = $conn->prepare("SELECT coins FROM users WHERE id = ?");
            $stmt_user->bind_param("i", $user_id);
            $stmt_user->execute();
            $user_result = $stmt_user->get_result();
            $user_row = $user_result->fetch_assoc();
            $coins = $user_row['coins'] ?? 0;
            $stmt_user->close();

            // Generate session token for new user
            $session_token = bin2hex(random_bytes(32));
            $expires_at = date('Y-m-d H:i:s', strtotime('+30 days'));

            $stmt = $conn->prepare("INSERT INTO session_tokens (user_id, device_id, session_token, expires_at) VALUES (?, ?, ?, ?)");
            $stmt->bind_param("isss", $user_id, $device_id, $session_token, $expires_at);
            $stmt->execute();

            // Check daily checkin status for new user (should be true since they're new)
            $can_claim = checkDailyCheckinStatus($user_id, $conn);

            sendResponse(200, 'Signup successful', [
                'user_id' => $user_id,
                'email' => $email,
                'refercode' => $refercode,
                'coins' => $coins,
                'can_claim' => $can_claim
            ], $session_token);
        } else {
            sendResponse(500, 'Signup failed');
        }
    }

    $stmt->close();
    $conn->close();
} else {
    sendResponse(405, 'Method Not Allowed');
}
?>