<?php
/**
 * Agent Model
 * Handles agent authentication and data with encryption
 */

class Agent {
    private $conn;
    private $table_name = "agents";

    public $id;
    public $username;
    public $password_hash;
    public $role;
    public $full_name;
    public $email;
    public $phone;
    public $is_active;
    public $last_login;
    public $created_at;
    public $updated_at;

    public function __construct($db) {
        $this->conn = $db;
        // Load encryption middleware
        require_once __DIR__ . '/../middleware/DataEncryption.php';
    }

    /**
     * Authenticate agent - with encrypted data retrieval
     */
    public function authenticate($username, $password) {
        $query = "SELECT id, username, password_hash, role, full_name, email, phone, is_active
                  FROM " . $this->table_name . "
                  WHERE username = :username AND is_active = 1
                  LIMIT 1";

        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':username', $username);
        $stmt->execute();

        if ($stmt->rowCount() > 0) {
            $row = $stmt->fetch(PDO::FETCH_ASSOC);

            // TEMPORARY: Try new encryption first, then fallback to old method
            $passwordValid = false;

            // Try new Argon2ID encryption
            if (DataEncryption::verifyPassword($password, $row['password_hash'])) {
                $passwordValid = true;
            }
            // Fallback to old password_hash for existing users
            elseif (password_verify($password, $row['password_hash'])) {
                $passwordValid = true;
                // TODO: Re-hash with Argon2ID on next login
            }

            if ($passwordValid) {
                // Update last login
                $this->updateLastLogin($row['id']);

                // TEMPORARY: Try to decrypt, fallback to raw data if decryption fails
                $email = $row['email'];
                $phone = $row['phone'];

                try {
                    $email = DataEncryption::decrypt($row['email']);
                } catch (Exception $e) {
                    // Keep raw data if decryption fails
                    $email = $row['email'];
                }

                try {
                    $phone = DataEncryption::decrypt($row['phone']);
                } catch (Exception $e) {
                    // Keep raw data if decryption fails
                    $phone = $row['phone'];
                }

                return [
                    'id' => $row['id'],
                    'username' => $row['username'],
                    'role' => $row['role'],
                    'full_name' => $row['full_name'],
                    'email' => $email,
                    'phone' => $phone
                ];
            }
        }

        return false;
    }

    /**
     * Update last login timestamp
     */
    private function updateLastLogin($agent_id) {
        $query = "UPDATE " . $this->table_name . "
                  SET last_login = NOW()
                  WHERE id = :id";

        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':id', $agent_id);
        $stmt->execute();
    }

    /**
     * Get agent by ID - with decrypted data
     */
    public function getById($id) {
        $query = "SELECT id, username, role, full_name, email, phone, is_active, last_login, created_at, updated_at
                  FROM " . $this->table_name . "
                  WHERE id = :id
                  LIMIT 1";

        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':id', $id);
        $stmt->execute();

        $agent = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($agent) {
            // Decrypt sensitive data
            $agent['email'] = DataEncryption::decrypt($agent['email']);
            $agent['phone'] = DataEncryption::decrypt($agent['phone']);
        }

        return $agent;
    }

    /**
     * Get all agents - with decrypted data
     */
    public function getAll($filters = []) {
        $query = "SELECT id, username, role, full_name, email, phone, is_active, last_login, created_at, updated_at
                  FROM " . $this->table_name;

        $conditions = [];
        $params = [];

        if (isset($filters['role'])) {
            $conditions[] = "role = :role";
            $params[':role'] = $filters['role'];
        }

        if (isset($filters['is_active'])) {
            $conditions[] = "is_active = :is_active";
            $params[':is_active'] = $filters['is_active'];
        }

        if (!empty($conditions)) {
            $query .= " WHERE " . implode(" AND ", $conditions);
        }

        $query .= " ORDER BY created_at DESC";

        $stmt = $this->conn->prepare($query);

        foreach ($params as $key => $value) {
            $stmt->bindValue($key, $value);
        }

        $stmt->execute();
        $agents = $stmt->fetchAll(PDO::FETCH_ASSOC);

        // Decrypt sensitive data for each agent
        foreach ($agents as &$agent) {
            $agent['email'] = DataEncryption::decrypt($agent['email']);
            $agent['phone'] = DataEncryption::decrypt($agent['phone']);
        }

        return $agents;
    }

    /**
     * Create new agent - with encrypted data storage
     */
    public function create($data) {
        $query = "INSERT INTO " . $this->table_name . "
                  (username, password_hash, role, full_name, email, phone)
                  VALUES (:username, :password_hash, :role, :full_name, :email, :phone)";

        $stmt = $this->conn->prepare($query);

        // Hash password with Argon2ID
        $password_hash = DataEncryption::hashPassword($data['password']);

        // Encrypt sensitive data
        $encryptedEmail = DataEncryption::encrypt($data['email']);
        $encryptedPhone = DataEncryption::encrypt($data['phone']);

        $stmt->bindParam(':username', $data['username']);
        $stmt->bindParam(':password_hash', $password_hash);
        $stmt->bindParam(':role', $data['role']);
        $stmt->bindParam(':full_name', $data['full_name']);
        $stmt->bindParam(':email', $encryptedEmail);
        $stmt->bindParam(':phone', $encryptedPhone);

        if ($stmt->execute()) {
            return $this->conn->lastInsertId();
        }

        return false;
    }

    /**
     * Update agent - with encrypted data storage
     */
    public function update($id, $data) {
        $fields = [];
        $params = [':id' => $id];

        if (isset($data['username'])) {
            $fields[] = "username = :username";
            $params[':username'] = $data['username'];
        }

        if (isset($data['role'])) {
            $fields[] = "role = :role";
            $params[':role'] = $data['role'];
        }

        if (isset($data['full_name'])) {
            $fields[] = "full_name = :full_name";
            $params[':full_name'] = $data['full_name'];
        }

        if (isset($data['email'])) {
            $fields[] = "email = :email";
            // Encrypt email before storage
            $params[':email'] = DataEncryption::encrypt($data['email']);
        }

        if (isset($data['phone'])) {
            $fields[] = "phone = :phone";
            // Encrypt phone before storage
            $params[':phone'] = DataEncryption::encrypt($data['phone']);
        }

        if (isset($data['is_active'])) {
            $fields[] = "is_active = :is_active";
            $params[':is_active'] = $data['is_active'];
        }

        if (isset($data['password'])) {
            $fields[] = "password_hash = :password_hash";
            // Hash password with Argon2ID
            $params[':password_hash'] = DataEncryption::hashPassword($data['password']);
        }

        if (empty($fields)) {
            return false;
        }

        $query = "UPDATE " . $this->table_name . "
                  SET " . implode(", ", $fields) . ", updated_at = NOW()
                  WHERE id = :id";

        $stmt = $this->conn->prepare($query);

        foreach ($params as $key => $value) {
            $stmt->bindValue($key, $value);
        }

        return $stmt->execute();
    }

    /**
     * Delete agent
     */
    public function delete($id) {
        $query = "DELETE FROM " . $this->table_name . " WHERE id = :id";
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(':id', $id);
        return $stmt->execute();
    }

    /**
     * Check if username exists
     */
    public function usernameExists($username, $exclude_id = null) {
        $query = "SELECT id FROM " . $this->table_name . " WHERE username = :username";
        $params = [':username' => $username];

        if ($exclude_id) {
            $query .= " AND id != :exclude_id";
            $params[':exclude_id'] = $exclude_id;
        }

        $stmt = $this->conn->prepare($query);

        foreach ($params as $key => $value) {
            $stmt->bindValue($key, $value);
        }

        $stmt->execute();
        return $stmt->rowCount() > 0;
    }

    /**
     * Get agent statistics
     */
    public function getStats() {
        $query = "SELECT
                    role,
                    COUNT(*) as count,
                    SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) as active_count
                  FROM " . $this->table_name . "
                  GROUP BY role";

        $stmt = $this->conn->prepare($query);
        $stmt->execute();

        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}
?>
