"""Validate production/staging environment files before release."""

from __future__ import annotations

import argparse
import re
from pathlib import Path

PLACEHOLDER_PATTERNS = (
    "CHANGE_ME",
    "your-",
    "your_",
    "example.com",
    "localhost",
    "minioadmin",
)

REQUIRED_ALWAYS = (
    "APP_ENV",
    "DATABASE_URL",
    "JWT_SECRET_KEY",
    "REDIS_URL",
)

REQUIRED_SMTP = (
    "SMTP_HOST",
    "SMTP_PORT",
    "SMTP_USER",
    "SMTP_PASSWORD",
    "SMTP_FROM_EMAIL",
    "SMTP_FROM_NAME",
)

REQUIRED_OSS = (
    "OSS_ENDPOINT",
    "OSS_ACCESS_KEY_ID",
    "OSS_ACCESS_KEY_SECRET",
    "OSS_BUCKET_NAME",
)


def parse_env_file(path: Path) -> dict[str, str]:
    values: dict[str, str] = {}
    for line_number, raw_line in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1):
        line = raw_line.strip()
        if not line or line.startswith("#"):
            continue
        if "=" not in line:
            raise ValueError(f"{path}:{line_number}: invalid env line without '='")
        key, value = line.split("=", 1)
        values[key.strip()] = value.strip().strip('"').strip("'")
    return values


def is_enabled(value: str | None) -> bool:
    return str(value or "").lower() in {"1", "true", "yes", "on"}


def has_placeholder(value: str) -> bool:
    lowered = value.lower()
    return any(pattern.lower() in lowered for pattern in PLACEHOLDER_PATTERNS)


def validate(values: dict[str, str], strict_external: bool) -> list[str]:
    errors: list[str] = []

    for key in REQUIRED_ALWAYS:
        if not values.get(key):
            errors.append(f"missing required env: {key}")

    app_env = values.get("APP_ENV") or values.get("ENVIRONMENT")
    if app_env not in {"staging", "production"}:
        errors.append("APP_ENV must be staging or production")

    jwt_secret = values.get("JWT_SECRET_KEY", "")
    if len(jwt_secret) < 32:
        errors.append("JWT_SECRET_KEY must be at least 32 characters")

    if is_enabled(values.get("AUTO_CREATE_SCHEMA")):
        errors.append("AUTO_CREATE_SCHEMA must not be enabled outside development")

    if values.get("DEBUG", "false").lower() == "true" and app_env == "production":
        errors.append("DEBUG must be false in production")

    external_requirements = []
    if is_enabled(values.get("ENABLE_EMAIL_DELIVERY")):
        external_requirements.extend(REQUIRED_SMTP)
    if strict_external:
        external_requirements.extend(REQUIRED_OSS)
    if strict_external or is_enabled(values.get("ENABLE_REDIS_SESSIONS")):
        external_requirements.append("REDIS_URL")

    for key in sorted(set(external_requirements)):
        if not values.get(key):
            errors.append(f"missing external-service env: {key}")

    secret_like = re.compile(r"(SECRET|PASSWORD|TOKEN|KEY)")
    for key, value in values.items():
        if value and has_placeholder(value) and (strict_external or secret_like.search(key)):
            errors.append(f"placeholder value remains in {key}")

    if values.get("GENERATED_FILES_HOST_DIR") and app_env == "production":
        if "staging" in values["GENERATED_FILES_HOST_DIR"]:
            errors.append("GENERATED_FILES_HOST_DIR must not point at staging in production")

    return errors


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("env_file", type=Path, nargs="?", help="Env file to validate. Omit with --from-environ.")
    parser.add_argument(
        "--from-environ",
        action="store_true",
        help="Validate the current process environment instead of reading an env file.",
    )
    parser.add_argument(
        "--strict-external",
        action="store_true",
        help="Require Redis sessions and OSS credentials for production readiness. SMTP is required only when ENABLE_EMAIL_DELIVERY=true.",
    )
    args = parser.parse_args()

    if args.from_environ:
        import os

        values = dict(os.environ)
        source = "process environment"
    else:
        if args.env_file is None:
            parser.error("env_file is required unless --from-environ is set")
        values = parse_env_file(args.env_file)
        source = str(args.env_file)

    errors = validate(values, args.strict_external)
    if errors:
        for error in errors:
            print(f"ERROR: {error}")
        return 1

    print(f"OK: {source} passed release env validation")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
