from __future__ import annotations

import os
import re
from io import StringIO
from pathlib import Path

from django.conf import settings
from django.core.management import call_command

from portal.models import PortalSetting

ENV_PATH = Path(settings.BASE_DIR) / ".env"

ENV_KEYS = (
    "DEBUG",
    "SKIP_DEMO_SEED",
    "ALLOWED_HOSTS",
    "SECRET_KEY",
    "DATABASE_URL",
)


def read_env_file() -> dict[str, str]:
    if not ENV_PATH.is_file():
        return {}
    out: dict[str, str] = {}
    for line in ENV_PATH.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#") or "=" not in line:
            continue
        key, _, val = line.partition("=")
        out[key.strip()] = val.strip().strip('"').strip("'")
    return out


def write_env_file(updates: dict[str, str]) -> None:
    current = read_env_file()
    current.update({k: v for k, v in updates.items() if v is not None})
    lines: list[str] = []
    if ENV_PATH.is_file():
        seen = set()
        for line in ENV_PATH.read_text(encoding="utf-8").splitlines():
            if "=" in line and not line.strip().startswith("#"):
                key = line.split("=", 1)[0].strip()
                if key in updates:
                    lines.append(f"{key}={updates[key]}")
                    seen.add(key)
                    continue
            lines.append(line)
        for key in ENV_KEYS:
            if key in updates and key not in seen:
                lines.append(f"{key}={updates[key]}")
    else:
        for key in ENV_KEYS:
            if key in current:
                lines.append(f"{key}={current[key]}")
    ENV_PATH.write_text("\n".join(lines) + "\n", encoding="utf-8")


def mask_secret(value: str, visible: int = 4) -> str:
    if not value:
        return ""
    if len(value) <= visible * 2:
        return "*" * len(value)
    return value[:visible] + "…" + value[-visible:]


def run_migrations() -> str:
    buf = StringIO()
    call_command("migrate", verbosity=2, stdout=buf, stderr=buf)
    return buf.getvalue()


def run_makemigrations() -> str:
    buf = StringIO()
    call_command("makemigrations", verbosity=2, stdout=buf, stderr=buf)
    return buf.getvalue()


def get_portal_settings() -> dict[str, str]:
    return {s.key: s.value for s in PortalSetting.objects.all()}


def set_portal_setting(key: str, value: str, description: str = "") -> None:
    PortalSetting.objects.update_or_create(
        key=key,
        defaults={"value": value, "description": description},
    )


def database_summary() -> str:
    db = settings.DATABASES["default"]
    engine = db.get("ENGINE", "")
    if "mysql" in engine:
        return f"MySQL {db.get('HOST')}:{db.get('PORT')}/{db.get('NAME')}"
    if "sqlite" in engine:
        return f"SQLite {db.get('NAME')}"
    return engine


def table_counts() -> list[tuple[str, int]]:
    from django.db import connection

    tables = [
        "users",
        "reviews",
        "articles",
        "data_extractions",
    ]
    counts = []
    with connection.cursor() as cursor:
        for table in tables:
            try:
                cursor.execute(f"SELECT COUNT(*) FROM `{table}`")
                counts.append((table, cursor.fetchone()[0]))
            except Exception:
                counts.append((table, -1))
    return counts
