import os
import socket
import tempfile
import time
from datetime import timedelta
from pathlib import Path
from urllib.parse import urlparse

from django.conf import settings
from django.core import checks
from django.core.cache import cache
from django.db import connection
from django.db.migrations.executor import MigrationExecutor
from django.utils import timezone


def _result(key, label, status, message, duration_ms=0, detail=""):
    return {
        "key": key,
        "label": label,
        "status": status,
        "message": message,
        "duration_ms": round(duration_ms, 1),
        "detail": detail,
    }


def _timed(key, label, callback):
    started = time.perf_counter()
    try:
        status, message, detail = callback()
    except Exception as exc:  # health checks must never crash the page
        status, message, detail = "error", "Falhou", str(exc)
    return _result(key, label, status, message, (time.perf_counter() - started) * 1000, detail)


def run_health_checks(*, include_details=False):
    def database_check():
        with connection.cursor() as cursor:
            cursor.execute("SELECT 1")
            value = cursor.fetchone()[0]
        return ("ok", "Ligação operacional", f"Resposta SQL: {value}" if include_details else "")

    def migration_check():
        executor = MigrationExecutor(connection)
        targets = executor.loader.graph.leaf_nodes()
        plan = executor.migration_plan(targets)
        if plan:
            detail = ", ".join(f"{migration.app_label}.{migration.name}" for migration, _ in plan[:8])
            return ("warning", f"{len(plan)} migrações pendentes", detail if include_details else "")
        return ("ok", "Base de dados atualizada", "Sem migrações pendentes" if include_details else "")

    def cache_check():
        key = f"k4w-health-{time.time_ns()}"
        cache.set(key, "ok", timeout=10)
        value = cache.get(key)
        cache.delete(key)
        if value != "ok":
            return ("error", "Leitura do cache falhou", "")
        return ("ok", "Leitura e escrita válidas", "")

    def media_check():
        media_root = Path(settings.MEDIA_ROOT)
        media_root.mkdir(parents=True, exist_ok=True)
        fd, filename = tempfile.mkstemp(prefix="k4w-health-", suffix=".tmp", dir=media_root)
        try:
            os.write(fd, b"k4w")
        finally:
            os.close(fd)
        Path(filename).unlink(missing_ok=True)
        return ("ok", "Armazenamento gravável", "")

    def static_check():
        logo = Path(settings.BASE_DIR) / "static" / "branding" / "kreate4web-logo-horizontal.png"
        if logo.exists() and logo.stat().st_size > 0:
            return ("ok", "Recursos visuais disponíveis", "")
        return ("error", "Logótipo horizontal em falta", "")

    def django_check():
        problems = checks.run_checks()
        serious = [item for item in problems if item.level >= checks.ERROR]
        warnings = [item for item in problems if checks.WARNING <= item.level < checks.ERROR]
        if serious:
            detail = "; ".join(str(item) for item in serious[:5]) if include_details else ""
            return ("error", f"{len(serious)} erros de configuração", detail)
        if warnings:
            detail = "; ".join(str(item) for item in warnings[:5]) if include_details else ""
            return ("warning", f"{len(warnings)} avisos de configuração", detail)
        return ("ok", "Configuração Django válida", "")

    def email_check():
        backend = settings.EMAIL_BACKEND.rsplit(".", 1)[-1]
        if "console" in settings.EMAIL_BACKEND.lower():
            return ("warning", "Email em modo de consola", backend if include_details else "")
        if not settings.EMAIL_HOST or not settings.DEFAULT_FROM_EMAIL:
            return ("warning", "SMTP incompleto", "Configure EMAIL_HOST e DEFAULT_FROM_EMAIL" if include_details else "")
        return ("ok", "Configuração SMTP preenchida", backend if include_details else "")

    def monitoring_check():
        try:
            from monitoring.models import MonitorIncident, WebsiteMonitor
        except Exception as exc:
            return ("warning", "Monitorização não disponível", str(exc) if include_details else "")
        active = WebsiteMonitor.objects.filter(is_active=True).count()
        open_incidents = MonitorIncident.objects.filter(
            status__in=[MonitorIncident.Status.OPEN, MonitorIncident.Status.ACKNOWLEDGED]
        ).count()
        overdue = WebsiteMonitor.objects.filter(is_active=True, next_check_at__lt=timezone.now() - timedelta(minutes=15)).count()
        if open_incidents:
            return ("warning", f"{open_incidents} incidente(s) aberto(s)", f"{active} monitores ativos; {overdue} atrasados" if include_details else "")
        if overdue:
            return ("warning", f"{overdue} monitor(es) atrasado(s)", f"{active} monitores ativos" if include_details else "")
        return ("ok", f"{active} monitores operacionais", "Sem incidentes abertos" if include_details else "")

    def broker_check():
        parsed = urlparse(settings.CELERY_BROKER_URL)
        if parsed.scheme not in {"redis", "rediss"}:
            return ("warning", "Broker não verificado", parsed.scheme if include_details else "")
        host = parsed.hostname or "127.0.0.1"
        port = parsed.port or 6379
        try:
            with socket.create_connection((host, port), timeout=0.35):
                return ("ok", "Redis acessível", f"{host}:{port}" if include_details else "")
        except OSError:
            return ("warning", "Redis indisponível", f"{host}:{port}" if include_details else "")

    checks_list = [
        _timed("database", "Base de dados", database_check),
        _timed("migrations", "Migrações", migration_check),
        _timed("django", "Configuração Django", django_check),
        _timed("cache", "Cache", cache_check),
        _timed("media", "Ficheiros e media", media_check),
        _timed("static", "Recursos estáticos", static_check),
        _timed("email", "Email", email_check),
        _timed("celery", "Celery / Redis", broker_check),
        _timed("monitoring", "Monitorização de websites", monitoring_check),
    ]
    errors = sum(item["status"] == "error" for item in checks_list)
    warnings = sum(item["status"] == "warning" for item in checks_list)
    overall = "error" if errors else ("warning" if warnings else "ok")
    return {
        "status": overall,
        "checked_at": timezone.now().isoformat(),
        "version": settings.K4W_VERSION,
        "environment": settings.K4W_ENVIRONMENT,
        "checks": checks_list,
        "summary": {
            "total": len(checks_list),
            "ok": sum(item["status"] == "ok" for item in checks_list),
            "warning": warnings,
            "error": errors,
        },
    }
