<?php

class AuthController {

    // ─── POST /api/auth/register ──────────────────────────────────────────────
    // users columns: id, name, email, phone, address, password, created_at, id_verified, verification_level
    public static function register(): void {
        $body = getJsonBody();

        $name     = trim($body['name']     ?? '');
        $email    = trim($body['email']    ?? '');
        $password = trim($body['password'] ?? '');
        $phone    = trim($body['phone']    ?? '');
        $address  = trim($body['address']  ?? '');

        // Validation
        $errors = [];
        if (!$name)                                          $errors['name']     = 'Name is required';
        if (!filter_var($email, FILTER_VALIDATE_EMAIL))     $errors['email']    = 'Valid email is required';
        if (strlen($password) < 6)                          $errors['password'] = 'Password must be at least 6 characters';
        if ($errors) sendError('Validation failed', 422, $errors);

        $db = getDb();

        // Check duplicate email
        $stmt = $db->prepare("SELECT id FROM users WHERE email = ? LIMIT 1");
        $stmt->bind_param('s', $email);
        $stmt->execute();
        $stmt->store_result();
        if ($stmt->num_rows > 0) sendError('Email already registered', 409);
        $stmt->close();

        // Hash password & insert
        $hash = password_hash($password, PASSWORD_BCRYPT);

        $stmt = $db->prepare(
            "INSERT INTO users (name, email, password, phone, address, verification_level, created_at)
             VALUES (?, ?, ?, ?, ?, 'none', NOW())"
        );
        $stmt->bind_param('sssss', $name, $email, $hash, $phone, $address);
        $stmt->execute();
        $userId = $stmt->insert_id;
        $stmt->close();

        // Sync with organized addresses table
        if ($address) {
            $stmt = $db->prepare(
                "INSERT INTO addresses (user_id, address_type, full_name, phone, address, city, state, pincode, is_default)
                 VALUES (?, 'home', ?, ?, ?, '', '', '', 1)"
            );
            $stmt->bind_param('isss', $userId, $name, $phone, $address);
            $stmt->execute();
            $stmt->close();
        }

        $token = self::generateToken($userId, $email);

        sendSuccess([
            'user'  => [
                'id'      => $userId,
                'name'    => $name,
                'email'   => $email,
                'phone'   => $phone,
                'address' => $address,
            ],
            'token' => $token,
        ], 'Registration successful', 201);
    }

    // ─── POST /api/auth/login ─────────────────────────────────────────────────
    public static function login(): void {
        $body = getJsonBody();

        $email    = trim($body['email']    ?? '');
        $password = trim($body['password'] ?? '');

        if (!$email || !$password) sendError('Email and password are required', 422);

        $db   = getDb();
        $stmt = $db->prepare(
            "SELECT id, name, email, phone, password, id_verified, verification_level, status
             FROM users WHERE email = ? LIMIT 1"
        );
        $stmt->bind_param('s', $email);
        $stmt->execute();
        $user = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$user || !password_verify($password, $user['password'])) {
            sendError('Invalid email or password', 401);
        }

        // Trigger rental status update to check for overdue items
        require_once __DIR__ . '/../services/RentalService.php';
        RentalService::updateStatuses($db, (int)$user['id']);

        // Refetch status to see if the user was just blocked
        $updatedRes = $db->query("SELECT status FROM users WHERE id = " . (int)$user['id']);
        $updatedUser = $updatedRes->fetch_assoc();

        if (isset($updatedUser['status']) && $updatedUser['status'] == 'blocked') {
            $token = self::generateToken($user['id'], $user['email']);
            sendError('Your account has been blocked due to outstanding penalties or damages. Please contact support.', 403, ['token' => $token, 'user' => [
                'id'                 => $user['id'],
                'name'               => $user['name'],
                'email'              => $user['email'],
                'phone'              => $user['phone'],
                'id_verified'        => (bool)$user['id_verified'],
                'verification_level' => $user['verification_level'],
            ]]);
        }

        $token = self::generateToken($user['id'], $user['email']);

        sendSuccess([
            'user'  => [
                'id'                 => $user['id'],
                'name'               => $user['name'],
                'email'              => $user['email'],
                'phone'              => $user['phone'],
                'id_verified'        => (bool)$user['id_verified'],
                'verification_level' => $user['verification_level'],
            ],
            'token' => $token,
        ], 'Login successful');
    }

    // ─── GET /api/user/profile ────────────────────────────────────────────────
    public static function profile(): void {
        $auth = self::requireAuth();

        $db   = getDb();
        $stmt = $db->prepare(
            "SELECT id, name, email, phone, address, id_verified, verification_level, created_at
             FROM users WHERE id = ? LIMIT 1"
        );
        $stmt->bind_param('i', $auth['id']);
        $stmt->execute();
        $row = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$row) sendError('User not found', 404);

        $row['id_verified'] = (bool)$row['id_verified'];
        sendSuccess($row);
    }

    // ─── PUT /api/user/profile ─────────────────────────────────────────────────
    public static function updateProfile(): void {
        $auth = self::requireAuth();
        $body = getJsonBody();

        $name    = trim($body['name']    ?? '');
        $phone   = trim($body['phone']   ?? '');
        $address = trim($body['address'] ?? '');

        $errors = [];
        if (!$name) $errors['name'] = 'Name is required';
        if ($errors) sendError('Validation failed', 422, $errors);

        $db   = getDb();
        $stmt = $db->prepare(
            "UPDATE users SET name = ?, phone = ?, address = ? WHERE id = ?"
        );
        $stmt->bind_param('sssi', $name, $phone, $address, $auth['id']);
        $stmt->execute();
        $stmt->close();

        // Return updated profile
        $stmt = $db->prepare(
            "SELECT id, name, email, phone, address, id_verified, verification_level, created_at
             FROM users WHERE id = ? LIMIT 1"
        );
        $stmt->bind_param('i', $auth['id']);
        $stmt->execute();
        $row = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        $row['id_verified'] = (bool)$row['id_verified'];
        sendSuccess($row, 'Profile updated successfully');
    }

    // ─── POST /api/user/change-password ───────────────────────────────────────
    public static function changePassword(): void {
        $auth = self::requireAuth();
        $body = getJsonBody();

        $currentPassword = trim($body['current_password'] ?? '');
        $newPassword     = trim($body['new_password']     ?? '');
        $confirmPassword = trim($body['confirm_password'] ?? '');

        $errors = [];
        if (!$currentPassword)              $errors['current_password'] = 'Current password is required';
        if (strlen($newPassword) < 6)       $errors['new_password']     = 'New password must be at least 6 characters';
        if ($newPassword !== $confirmPassword) $errors['confirm_password'] = 'Passwords do not match';
        if ($errors) sendError('Validation failed', 422, $errors);

        $db   = getDb();
        $stmt = $db->prepare("SELECT password FROM users WHERE id = ? LIMIT 1");
        $stmt->bind_param('i', $auth['id']);
        $stmt->execute();
        $row  = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$row || !password_verify($currentPassword, $row['password'])) {
            sendError('Current password is incorrect', 401);
        }

        $hash = password_hash($newPassword, PASSWORD_BCRYPT);
        $stmt = $db->prepare("UPDATE users SET password = ? WHERE id = ?");
        $stmt->bind_param('si', $hash, $auth['id']);
        $stmt->execute();
        $stmt->close();

        sendSuccess(null, 'Password changed successfully');
    }

    // ─── POST /api/auth/forgot-password ───────────────────────────────────────
    public static function forgotPassword(): void {
        $body  = getJsonBody();
        $email = trim($body['email'] ?? '');

        if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            sendError('A valid email address is required', 422);
        }

        $db = getDb();

        // 1. Ensure password_resets table exists
        $db->query("CREATE TABLE IF NOT EXISTS password_resets (
            id INT PRIMARY KEY AUTO_INCREMENT,
            email VARCHAR(100) NOT NULL,
            token VARCHAR(100) NOT NULL,
            expires_at DATETIME NOT NULL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            INDEX idx_token (token),
            INDEX idx_email (email)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

        // 2. Check if user exists
        $stmt = $db->prepare("SELECT id FROM users WHERE email = ? LIMIT 1");
        $stmt->bind_param('s', $email);
        $stmt->execute();
        if ($stmt->get_result()->num_rows === 0) {
            // Security: Don't reveal if email exists, but for this project we'll show error for clarity
            sendError('Email not found in our system', 404);
        }
        $stmt->close();

        // 3. Generate reset token
        $token = bin2hex(random_bytes(32)); // 64 chars

        // 4. Delete old tokens for this email
        $stmt = $db->prepare("DELETE FROM password_resets WHERE email = ?");
        $stmt->bind_param('s', $email);
        $stmt->execute();
        $stmt->close();

        // 5. Store new token (expires in 1 hour)
        $stmt = $db->prepare("INSERT INTO password_resets (email, token, expires_at) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 1 HOUR))");
        $stmt->bind_param('ss', $email, $token);
        $stmt->execute();
        $stmt->close();

        // 6. Send reset email
        $mailSent = MailService::sendPasswordReset($email, $token);

        // 7. Return success (Secure: do not return token)
        sendSuccess([
            'email' => $email,
            'message' => 'If an account exists with this email, a reset link has been sent.'
        ], 'Password reset process initiated');
    }

    // ─── POST /api/auth/reset-password ────────────────────────────────────────
    public static function resetPassword(): void {
        $body = getJsonBody();

        $token           = trim($body['token']            ?? '');
        $newPassword     = trim($body['new_password']     ?? '');
        $confirmPassword = trim($body['confirm_password'] ?? '');

        if (!$token)                        sendError('Reset token is required', 422);
        if (strlen($newPassword) < 6)       sendError('Password must be at least 6 characters', 422);
        if ($newPassword !== $confirmPassword) sendError('Passwords do not match', 422);

        $db = getDb();

        // 1. Verify token
        $stmt = $db->prepare("SELECT email FROM password_resets WHERE token = ? AND expires_at > NOW() LIMIT 1");
        $stmt->bind_param('s', $token);
        $stmt->execute();
        $res = $stmt->get_result();
        $reset = $res->fetch_assoc();
        $stmt->close();

        if (!$reset) {
            sendError('Invalid or expired reset token', 401);
        }

        $email = $reset['email'];

        // 2. Update user password
        $hash = password_hash($newPassword, PASSWORD_BCRYPT);
        $stmt = $db->prepare("UPDATE users SET password = ? WHERE email = ?");
        $stmt->bind_param('ss', $hash, $email);
        $stmt->execute();
        $stmt->close();

        // 3. Delete used token
        $stmt = $db->prepare("DELETE FROM password_resets WHERE email = ?");
        $stmt->bind_param('s', $email);
        $stmt->execute();
        $stmt->close();

        sendSuccess(null, 'Password has been reset successfully. You can now login with your new password.');
    }


    // ─── Token Helpers ────────────────────────────────────────────────────────

    public static function generateToken(int $userId, string $email): string {
        $secret  = 'shopnest_secret_key_2024';
        $payload = base64_encode(json_encode([
            'id'    => $userId,
            'email' => $email,
            'exp'   => time() + 86400 * 30,
        ]));
        $sig = hash_hmac('sha256', $payload, $secret);
        return $payload . '.' . $sig;
    }

    public static function verifyToken(string $token): ?array {
        $secret = 'shopnest_secret_key_2024';
        $parts  = explode('.', $token);
        if (count($parts) !== 2) return null;
        [$payload, $sig] = $parts;
        if (!hash_equals(hash_hmac('sha256', $payload, $secret), $sig)) return null;
        $data = json_decode(base64_decode($payload), true);
        if (!$data || $data['exp'] < time()) return null;
        return $data;
    }

    public static function requireAuth(): array {
        $token = getBearerToken();
        if (!$token) sendError('Unauthorized: No token provided', 401);
        $data = self::verifyToken($token);
        if (!$data) sendError('Unauthorized: Invalid or expired token', 401);
        
        // Check if user is blocked
        $db = getDb();
        $stmt = $db->prepare("SELECT status FROM users WHERE id = ? LIMIT 1");
        $stmt->bind_param('i', $data['id']);
        $stmt->execute();
        $user = $stmt->get_result()->fetch_assoc();
        $stmt->close();
        
        if ($user && isset($user['status']) && $user['status'] == 'blocked') {
            sendError('Your account has been blocked due to outstanding penalties or damages. Please contact support.', 403);
        }
        
        return $data;
    }
}
