<?php

class User
{
    private PDO $db;

    public function __construct()
    {
        $this->db = Database::getInstance();
    }

    public function findByUsername(string $username): ?array
    {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE username = :username LIMIT 1');
        $stmt->execute(['username' => $username]);
        $user = $stmt->fetch();
        return $user ?: null;
    }

    public function findById(int $id): ?array
    {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE id = :id LIMIT 1');
        $stmt->execute(['id' => $id]);
        $user = $stmt->fetch();
        return $user ?: null;
    }

    public function update(int $id, array $data): bool
    {
        $stmt = $this->db->prepare(
            'UPDATE users SET display_name = :display_name, email = :email, default_view = :default_view, default_language = :default_language, default_theme = :default_theme WHERE id = :id'
        );
        return $stmt->execute([
            'display_name'     => $data['display_name'],
            'email'            => $data['email'],
            'default_view'     => $data['default_view'] ?? 'grid',
            'default_language' => $data['default_language'] ?? 'en',
            'default_theme'    => $data['default_theme'] ?? 'system',
            'id'               => $id,
        ]);
    }

    public function updateAvatar(int $id, string $avatar): bool
    {
        $stmt = $this->db->prepare('UPDATE users SET avatar = :avatar WHERE id = :id');
        return $stmt->execute(['avatar' => $avatar, 'id' => $id]);
    }

    public function updatePassword(int $id, string $hashedPassword): bool
    {
        $stmt = $this->db->prepare('UPDATE users SET password = :password WHERE id = :id');
        return $stmt->execute([
            'password' => $hashedPassword,
            'id'       => $id,
        ]);
    }

    public function create(array $data): int
    {
        $stmt = $this->db->prepare(
            'INSERT INTO users (username, password, display_name, email, role, status, default_language)
             VALUES (:username, :password, :display_name, :email, :role, :status, :default_language)'
        );
        $stmt->execute([
            'username'        => $data['username'],
            'password'        => $data['password'],
            'display_name'    => $data['display_name'] ?? $data['username'],
            'email'           => $data['email'] ?? '',
            'role'            => $data['role'] ?? 'user',
            'status'          => $data['status'] ?? 'pending',
            'default_language' => 'en', // Always default to English for new users
        ]);
        return (int)$this->db->lastInsertId();
    }

    public function getAll(): array
    {
        $stmt = $this->db->query('SELECT id, username, display_name, email, role, status, created_at FROM users ORDER BY id ASC');
        return $stmt->fetchAll();
    }

    public function countAll(): int
    {
        return (int)$this->db->query('SELECT COUNT(*) FROM users')->fetchColumn();
    }

    public function countByStatus(string $status): int
    {
        $stmt = $this->db->prepare('SELECT COUNT(*) FROM users WHERE status = :status');
        $stmt->execute(['status' => $status]);
        return (int)$stmt->fetchColumn();
    }

    public function updateStatus(int $id, string $status): bool
    {
        $stmt = $this->db->prepare('UPDATE users SET status = :status WHERE id = :id');
        return $stmt->execute(['status' => $status, 'id' => $id]);
    }

    public function adminUpdate(int $id, array $data): bool
    {
        $stmt = $this->db->prepare(
            'UPDATE users SET display_name = :display_name, email = :email, role = :role, status = :status WHERE id = :id'
        );
        return $stmt->execute([
            'display_name' => $data['display_name'],
            'email'        => $data['email'],
            'role'         => $data['role'],
            'status'       => $data['status'],
            'id'           => $id,
        ]);
    }

    public function delete(int $id): bool
    {
        $stmt = $this->db->prepare('DELETE FROM users WHERE id = :id');
        return $stmt->execute(['id' => $id]);
    }

    public function findByEmail(string $email): ?array
    {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE email = :email LIMIT 1');
        $stmt->execute(['email' => $email]);
        $user = $stmt->fetch();
        return $user ?: null;
    }

    public function findByResetToken(string $token): ?array
    {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE password_reset_token = :token LIMIT 1');
        $stmt->execute(['token' => $token]);
        $user = $stmt->fetch();
        return $user ?: null;
    }

    public function setPasswordResetToken(int $id, string $token, string $expires): bool
    {
        $stmt = $this->db->prepare(
            'UPDATE users SET password_reset_token = :token, password_reset_expires = :expires WHERE id = :id'
        );
        return $stmt->execute([
            'token'   => $token,
            'expires' => $expires,
            'id'      => $id,
        ]);
    }

    public function updatePasswordAndClearToken(int $id, string $hashedPassword): bool
    {
        $stmt = $this->db->prepare(
            'UPDATE users SET password = :password, password_reset_token = NULL, password_reset_expires = NULL WHERE id = :id'
        );
        return $stmt->execute([
            'password' => $hashedPassword,
            'id'       => $id,
        ]);
    }

    public function hasAcceptedCookies(int $userId): bool
    {
        $stmt = $this->db->prepare('SELECT cookies_accepted FROM users WHERE id = :id LIMIT 1');
        $stmt->execute(['id' => $userId]);
        $result = $stmt->fetch();
        return $result && (bool)$result['cookies_accepted'];
    }

    public function acceptCookies(int $userId): bool
    {
        $stmt = $this->db->prepare(
            'UPDATE users SET cookies_accepted = 1, cookies_accepted_at = NOW() WHERE id = :id'
        );
        return $stmt->execute(['id' => $userId]);
    }

    public function updatePreference(int $userId, string $key, string $value): bool
    {
        $stmt = $this->db->prepare(
            "UPDATE users SET {$key} = :value WHERE id = :id"
        );
        return $stmt->execute([
            'value' => $value,
            'id' => $userId,
        ]);
    }

    public function setEmailVerificationToken(int $id, string $token, string $expires): bool
    {
        $stmt = $this->db->prepare(
            'UPDATE users SET email_verification_token = :token, email_verification_expires = :expires WHERE id = :id'
        );
        return $stmt->execute([
            'token'   => $token,
            'expires' => $expires,
            'id'      => $id,
        ]);
    }

    public function findByEmailVerificationToken(string $token): ?array
    {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE email_verification_token = :token LIMIT 1');
        $stmt->execute(['token' => $token]);
        $user = $stmt->fetch();
        return $user ?: null;
    }

    public function verifyEmail(int $id): bool
    {
        $stmt = $this->db->prepare(
            'UPDATE users SET status = :status, email_verified_at = NOW(), email_verification_token = NULL, email_verification_expires = NULL WHERE id = :id'
        );
        return $stmt->execute([
            'status' => 'approved',
            'id'     => $id,
        ]);
    }
}
