<?php

namespace Core\App\Models;

use PDO;
use Throwable;

class SecurityLog
{
    protected PDO $db;
    protected string $table = 'security_logs';

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

    /**
     * تسجيل حدث أمني
     */
    public static function log(string $type, string $message, ?string $url = null): void
    {
        try {
            $instance = new self();

            $stmt = $instance->db->prepare("
                INSERT INTO {$instance->table}
                    (type, ip, message, user_agent, url)
                VALUES
                    (:type, :ip, :message, :user_agent, :url)
            ");

            $stmt->execute([
                ':type'       => $type,
                ':ip'         => $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0',
                ':message'    => $message,
                ':user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null,
                ':url'        => $url ?? ($_SERVER['REQUEST_URI'] ?? null),
            ]);
        } catch (Throwable $e) {
            // لا نكسر الموقع لأي سبب
            error_log('[SecurityLog] ' . $e->getMessage());
        }
    }

    /**
     * جلب آخر السجلات
     */
    public function getLatest(int $limit = 50): array
    {
        $stmt = $this->db->prepare("
            SELECT *
            FROM {$this->table}
            ORDER BY id DESC
            LIMIT :limit
        ");

        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->execute();

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


    public function getLatestErrors(int $limit = 200, string $type = 'all', string $search = ''): array
    {
        $allowed = ['all', 'error', 'warning'];
        if (!in_array($type, $allowed, true)) {
            $type = 'all';
        }

        $sql = "SELECT * FROM {$this->table} WHERE 1=1";
        $params = [];

        if ($type !== 'all') {
            $sql .= " AND type = :type";
            $params[':type'] = $type;
        } else {
            $sql .= " AND type IN ('error','warning')";
        }

        if ($search !== '') {
            $sql .= " AND (message LIKE :search OR url LIKE :search OR ip LIKE :search)";
            $params[':search'] = '%' . $search . '%';
        }

        $sql .= " ORDER BY id DESC LIMIT :limit";
        $stmt = $this->db->prepare($sql);
        foreach ($params as $k => $v) {
            $stmt->bindValue($k, $v);
        }
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }


    public function getLatestByTypes(int $limit = 200, array $types = [], string $search = ''): array
    {
        $types = array_values(array_filter(array_unique(array_map('strval', $types))));
        $sql = "SELECT * FROM {$this->table} WHERE 1=1";
        $params = [];

        if ($types) {
            $placeholders = [];
            foreach ($types as $i => $type) {
                $key = ':type' . $i;
                $placeholders[] = $key;
                $params[$key] = $type;
            }
            $sql .= " AND type IN (" . implode(',', $placeholders) . ")";
        }

        if ($search !== '') {
            $sql .= " AND (message LIKE :search OR url LIKE :search OR ip LIKE :search OR user_agent LIKE :search)";
            $params[':search'] = '%' . $search . '%';
        }

        $sql .= " ORDER BY id DESC LIMIT :limit";
        $stmt = $this->db->prepare($sql);
        foreach ($params as $k => $v) {
            $stmt->bindValue($k, $v);
        }
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    public function getDistinctTypes(): array
    {
        $stmt = $this->db->query("SELECT DISTINCT type FROM {$this->table} ORDER BY type ASC");
        return array_values(array_filter(array_map('strval', $stmt->fetchAll(PDO::FETCH_COLUMN) ?: [])));
    }

    public function countByTypes(array $types): int
    {
        $types = array_values(array_filter(array_unique(array_map('strval', $types))));
        if (!$types) {
            return 0;
        }
        $placeholders = implode(',', array_fill(0, count($types), '?'));
        $stmt = $this->db->prepare("SELECT COUNT(*) FROM {$this->table} WHERE type IN ($placeholders)");
        $stmt->execute($types);
        return (int)$stmt->fetchColumn();
    }

    public function clearByTypes(array $types): int
    {
        $types = array_values(array_filter(array_unique(array_map('strval', $types))));
        if (!$types) {
            return 0;
        }
        $placeholders = implode(',', array_fill(0, count($types), '?'));
        $stmt = $this->db->prepare("DELETE FROM {$this->table} WHERE type IN ($placeholders)");
        $stmt->execute($types);
        return $stmt->rowCount();
    }

    public function clearByTypesOlderThan(array $types, int $days): int
    {
        $types = array_values(array_filter(array_unique(array_map('strval', $types))));
        if (!$types) {
            return 0;
        }
        $days = max(1, $days);
        $placeholders = implode(',', array_fill(0, count($types), '?'));
        $sql = "DELETE FROM {$this->table} WHERE type IN ($placeholders) AND created_at < (NOW() - INTERVAL ? DAY)";
        $stmt = $this->db->prepare($sql);
        $i = 1;
        foreach ($types as $type) {
            $stmt->bindValue($i++, $type);
        }
        $stmt->bindValue($i, $days, PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->rowCount();
    }

    /**
     * حذف سجل واحد
     */
    public function delete(int $id): bool
    {
        $stmt = $this->db->prepare("
            DELETE FROM {$this->table}
            WHERE id = :id
            LIMIT 1
        ");

        return $stmt->execute([':id' => $id]);
    }

    /**
     * تفريغ كل السجلات
     */
    public function clearAll(): bool
    {
        return $this->db->exec("TRUNCATE TABLE {$this->table}") !== false;
    }

    /**
     * جلب عدد السجلات حسب النوع
     */
    public function countByType(string $type): int
    {
        $stmt = $this->db->prepare("
            SELECT COUNT(*) 
            FROM {$this->table}
            WHERE type = :type
        ");

        $stmt->execute([':type' => $type]);
        return (int) $stmt->fetchColumn();
    }
}
