"""Read/update .env for Admin Connections; only allowlisted keys."""
import os
import re
from pathlib import Path
from typing import Dict, List, Optional

_BACKEND_DIR = Path(__file__).resolve().parent.parent.parent
_ROOT_DIR = _BACKEND_DIR.parent
ENV_FILE_PATH = Path(os.getenv("ENV_FILE_PATH", str(_ROOT_DIR / ".env")))

CONNECTIONS_ALLOWLIST = [
    "CLIENT_ID",
    "CLIENT_SECRET",
    "REFRESH_TOKEN",
    "REDIRECT_URI",
    "GOOGLE_SHEETS_ID",
    "GOOGLE_KPI_SHEETS_ID",
    "GOOGLE_SHEETS_TAB",
    "GOOGLE_CREDENTIALS_PATH",
    "GOOGLE_DAILY_FIGURES_SHEETS_ID",
    "WHATCONVERTS_API_TOKEN",
    "WHATCONVERTS_API_SECRET",
    "WHATCONVERTS_PROFILE_ID",
    "WHATCONVERTS_API_TOKEN_BUNBURY",
    "WHATCONVERTS_API_SECRET_BUNBURY",
    "WHATCONVERTS_PROFILE_ID_BUNBURY",
    "WHATCONVERTS_API_TOKEN_BUSSELTON",
    "WHATCONVERTS_API_SECRET_BUSSELTON",
    "WHATCONVERTS_PROFILE_ID_BUSSELTON",
    "WHATCONVERTS_API_TOKEN_MANDURAH",
    "WHATCONVERTS_API_SECRET_MANDURAH",
    "WHATCONVERTS_PROFILE_ID_MANDURAH",
    "XERO_TENANT_ID",
    "XERO_BUSSELTON_TENANT_ID",
    "XERO_MANDURAH_TENANT_ID",
    "XERO_MANAGEMENT_TENANT_ID",
    "XERO_ASSETS_TENANT_ID",
    "SENDGRID_API_KEY",
    "EMAIL_FROM",
    "APP_URL",
    "SITE_UPGRADE_MODE",
]

SECRET_KEYS = {
    "CLIENT_SECRET",
    "REFRESH_TOKEN",
    "SENDGRID_API_KEY",
    "WHATCONVERTS_API_SECRET",
    "WHATCONVERTS_API_SECRET_BUNBURY",
    "WHATCONVERTS_API_SECRET_BUSSELTON",
    "WHATCONVERTS_API_SECRET_MANDURAH",
}


def _mask(value: str) -> str:
    if not value or len(value) <= 4:
        return "••••" if value else ""
    return value[:2] + "••••••" + value[-2:]


def _parse_env_line(line: str) -> Optional[tuple]:
    line = line.strip()
    if not line or line.startswith("#"):
        return None
    m = re.match(r"^([A-Za-z_][A-Za-z0-9_]*)=(.*)$", line)
    if not m:
        return None
    key, raw = m.group(1), m.group(2)
    if raw.startswith('"') and raw.endswith('"'):
        value = raw[1:-1].replace('\\n', '\n').replace('\\"', '"')
    elif raw.startswith("'") and raw.endswith("'"):
        value = raw[1:-1]
    else:
        value = raw.strip()
    return (key, value)


def read_env_file() -> Dict[str, str]:
    result = {}
    if not ENV_FILE_PATH.exists():
        return result
    with open(ENV_FILE_PATH, "r") as f:
        for line in f:
            parsed = _parse_env_line(line)
            if parsed and parsed[0] in CONNECTIONS_ALLOWLIST:
                result[parsed[0]] = parsed[1]
    return result


def get_connections_masked() -> Dict[str, str]:
    from dotenv import load_dotenv
    load_dotenv(ENV_FILE_PATH)
    file_vals = read_env_file()
    out = {}
    for key in CONNECTIONS_ALLOWLIST:
        value = os.getenv(key) or file_vals.get(key) or ""
        if key in SECRET_KEYS and value:
            out[key] = _mask(value)
        else:
            out[key] = value
    return out


def update_env_file(updates: Dict[str, str]) -> None:
    allowed = {k: v for k, v in updates.items() if k in CONNECTIONS_ALLOWLIST}
    if not allowed:
        return
    lines = []
    if ENV_FILE_PATH.exists():
        with open(ENV_FILE_PATH, "r") as f:
            lines = f.readlines()
    keys_seen = set()
    new_lines = []
    for line in lines:
        parsed = _parse_env_line(line)
        if parsed and parsed[0] in allowed:
            if parsed[0] not in keys_seen:
                new_lines.append(_format_env_line(parsed[0], allowed[parsed[0]]))
                keys_seen.add(parsed[0])
            continue
        new_lines.append(line)
    for key, value in allowed.items():
        if key not in keys_seen:
            new_lines.append(_format_env_line(key, value))
    ENV_FILE_PATH.parent.mkdir(parents=True, exist_ok=True)
    with open(ENV_FILE_PATH, "w") as f:
        f.writelines(new_lines)


def _format_env_line(key: str, value: str) -> str:
    need_quote = "\n" in value or "#" in value or " " in value or (value.startswith('"') or value.startswith("'"))
    if need_quote:
        escaped = value.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
        return f'{key}="{escaped}"\n'
    return f"{key}={value}\n"
