from __future__ import annotations

import configparser
import importlib.machinery
import importlib.util
import sqlite3
import tempfile
import time
import unittest
from pathlib import Path

from phs.core.database import SCHEMA


class DashboardTests(unittest.TestCase):
    def setUp(self) -> None:
        loader = importlib.machinery.SourceFileLoader(
            "phs_whm_dashboard",
            str(Path(__file__).parents[1] / "whm-plugin" / "cgi" / "index.cgi"),
        )
        spec = importlib.util.spec_from_loader(loader.name, loader)
        assert spec is not None
        module = importlib.util.module_from_spec(spec)
        loader.exec_module(module)
        self.ui = module
        self.temp = tempfile.TemporaryDirectory()
        self.db_path = Path(self.temp.name) / "security.sqlite3"
        connection = sqlite3.connect(self.db_path)
        connection.row_factory = sqlite3.Row
        connection.executescript(SCHEMA)
        now = int(time.time())
        connection.execute(
            "INSERT INTO module_status(module,last_run,last_ok,status,detail,duration_ms) VALUES(?,?,?,?,?,?)",
            ("mail", now, now, "ok", "2 nuevos; 0 alertas; 0 suspensiones", 12),
        )
        connection.execute(
            "INSERT INTO events(ts,module,level,event_key,title,detail,action) VALUES(?,?,?,?,?,?,?)",
            (now, "mail", "warning", "test-event", "Alerta de correo", "Detalle", "notificado"),
        )
        connection.execute(
            "INSERT INTO mail_events(ts,kind,identity,cpanel_user,remote_ip,sender,protocol,msgid) VALUES(?,?,?,?,?,?,?,?)",
            (now, "smtp", "ventas@example.com", "example", "192.0.2.8", "ventas@example.com", "esmtpsa", "abc"),
        )
        connection.execute(
            """INSERT INTO system_metrics(
                   ts,cpu_percent,load1,load5,load15,cpu_count,memory_total,memory_used,
                   memory_percent,swap_total,swap_used,swap_percent,uptime_seconds
               ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)""",
            (now, 12.5, 0.42, 0.31, 0.20, 4, 8 * 1024**3, 3 * 1024**3, 37.5, 2 * 1024**3, 0, 0.0, 86400),
        )
        connection.execute(
            """INSERT INTO disk_status(
                   mount,device,filesystem,total_bytes,used_bytes,available_bytes,percent,inodes_percent,updated_at
               ) VALUES(?,?,?,?,?,?,?,?,?)""",
            ("/", "/dev/vda1", "/dev/vda1", 100 * 1024**3, 45 * 1024**3, 55 * 1024**3, 45.0, 0.0, now),
        )
        connection.execute(
            """INSERT INTO service_status(
                   name,display_name,enabled,installed,monitored,running,status,detail,updated_at
               ) VALUES(?,?,?,?,?,?,?,?,?)""",
            ("httpd", "Apache Web Server", 1, 1, 1, 1, "running", "", now),
        )
        connection.execute(
            """INSERT INTO account_usage(
                   username,domain,owner,plan,suspended,suspend_reason,disk_used_bytes,
                   disk_limit_bytes,disk_percent,quota_state,updated_at
               ) VALUES(?,?,?,?,?,?,?,?,?,?,?)""",
            ("fullacct", "full.example.com", "root", "Plan 10GB", 0, "", 11 * 1024**3,
             10 * 1024**3, 110.0, "full", now),
        )
        connection.execute(
            """INSERT INTO web_outages(
                   url,name,cpanel_user,started_at,ended_at,duration_seconds,
                   reason_category,reason_detail,http_code,resolved_ip
               ) VALUES(?,?,?,?,?,?,?,?,?,?)""",
            ("https://full.example.com", "Web llena", "fullacct", now - 600, now - 300,
             300, "HTTP 5xx", "HTTP 503", 503, "192.0.2.9"),
        )
        connection.commit()
        self.connection = connection
        self.cfg = configparser.ConfigParser()
        self.cfg.read_dict({
            "general": {"database": str(self.db_path)},
            "modules": {name: "yes" for name in self.ui.MODULES},
            "mail": {"window_seconds": "3600", "warning_limit": "100", "suspend_limit": "500"},
            "web_uptime": {"ssl_warning_days": "21", "targets_file": "/etc/phs-security/websites.conf"},
        })

    def tearDown(self) -> None:
        self.connection.close()
        self.temp.cleanup()

    def test_dashboard_renders_modern_sections(self) -> None:
        output = self.ui.dashboard(self.connection, self.cfg, "active")
        self.assertIn("Centro de protección", output)
        self.assertIn("Índice de salud", output)
        self.assertIn("Estado de módulos", output)
        self.assertIn("Actividad reciente", output)
        self.assertIn("Sitios caídos", output)
        self.assertIn("CPU actual", output)
        self.assertIn("Top de correo hoy", output)

    def test_all_views_render(self) -> None:
        pages = (
            self.ui.server_view(self.connection, self.cfg),
            self.ui.accounts_view(self.connection, self.cfg),
            self.ui.mail_view(self.connection, self.cfg),
            self.ui.websites_view(self.connection, self.cfg),
            self.ui.events_view(self.connection),
            self.ui.findings_view(self.connection),
            self.ui.blocked_view(self.connection),
            self.ui.config_view(self.cfg, Path("/etc/phs-security/config.ini")),
        )
        for page in pages:
            self.assertIn("class=\"", page)
            self.assertNotIn("Traceback", page)

    def test_server_and_mail_daily_views(self) -> None:
        server = self.ui.server_view(self.connection, self.cfg)
        mail = self.ui.mail_view(self.connection, self.cfg)
        self.assertIn("Todos los servicios WHM/cPanel", server)
        self.assertIn("Apache Web Server", server)
        self.assertIn("12.5%", server)
        accounts = self.ui.accounts_view(self.connection, self.cfg)
        websites = self.ui.websites_view(self.connection, self.cfg)
        self.assertIn("Top de cuentas de correo de hoy", mail)
        self.assertIn("Disco lleno", accounts)
        self.assertIn("full.example.com", accounts)
        self.assertIn("Webs con más caídas", websites)
        self.assertIn("HTTP 5xx", websites)
        self.assertIn("ventas@example.com", mail)

    def test_header_has_no_external_assets(self) -> None:
        output = self.ui.page_header("Resumen", "dashboard", "active", "1.2.0")
        self.assertNotIn("https://", output)
        self.assertIn("sidebar", output)
        self.assertIn("Servicio disponible", output)


if __name__ == "__main__":
    unittest.main()
