"""
Public installer downloads for CNPERP local (on-premise) deployments.
"""
import os
from typing import Any, Dict, List

from fastapi import APIRouter, HTTPException, Query, Request
from fastapi.responses import FileResponse

from app.core.config import settings
from app.core.production import is_production
from app.services.local_install_package_service import (
    get_package_path,
    package_filename,
    read_version,
)

router = APIRouter()


def _require_installer_key(request: Request) -> None:
    """In production, require X-Installer-Key when INSTALLER_DOWNLOAD_KEY is set."""
    expected = (settings.installer_download_key or "").strip()
    if not is_production() or not expected:
        return
    provided = (request.headers.get("x-installer-key") or request.query_params.get("key") or "").strip()
    if provided != expected:
        raise HTTPException(status_code=403, detail="Invalid or missing installer download key")


_LOCAL_SERVER_DIR = os.path.abspath(
    os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "deploy", "local-server")
)


def _public_base() -> str:
    return (settings.license_cloud_url or "").rstrip("/")


def _dl(filename: str) -> str:
    base = _public_base()
    if filename == "package":
        path = "/api/v1/installer/download/package"
    else:
        path = f"/api/v1/installer/download/{filename}"
    return f"{base}{path}" if base else path


def _installer_files() -> List[Dict[str, str]]:
    pkg_url = _dl("package")
    return [
        {
            "id": "full_package",
            "name": package_filename(),
            "description": "CNPERP folder — Windows, Linux, and macOS installers (recommended)",
            "url": pkg_url,
            "platform": "all",
            "primary": True,
        },
        {
            "id": "install_ps1",
            "name": "Install-CNPERP-Local.ps1",
            "description": "Windows — run in C:\\CNPERP as Administrator",
            "url": _dl("Install-CNPERP-Local.ps1"),
            "platform": "windows",
        },
        {
            "id": "install_sh",
            "name": "install-cnperp-local.sh",
            "description": "Linux / macOS — PostgreSQL, venv, cloud sync, optional systemd",
            "url": _dl("install-cnperp-local.sh"),
            "platform": "linux",
        },
        {
            "id": "start_ps1",
            "name": "Start-CNPERP-Server.ps1",
            "description": "Windows — start LAN server",
            "url": _dl("Start-CNPERP-Server.ps1"),
            "platform": "windows",
        },
        {
            "id": "start_sh",
            "name": "start-cnperp-server.sh",
            "description": "Linux / macOS — start LAN server",
            "url": _dl("start-cnperp-server.sh"),
            "platform": "linux",
        },
        {
            "id": "connect_ps1",
            "name": "Connect-Cloud.ps1",
            "description": "Windows — register cloud sync node",
            "url": _dl("Connect-Cloud.ps1"),
            "platform": "windows",
        },
        {
            "id": "connect_sh",
            "name": "connect-cloud.sh",
            "description": "Linux / macOS — register cloud sync node",
            "url": _dl("connect-cloud.sh"),
            "platform": "linux",
        },
    ]


@router.get("/local")
def local_install_info() -> Dict[str, Any]:
    """Metadata for the local server installation page."""
    return {
        "success": True,
        "product": "CNPERP Local Server",
        "deployment_mode": "local",
        "default_port": 8010,
        "cloud_url": settings.license_cloud_url,
        "version": read_version(),
        "package_download_url": _dl("package"),
        "package_folder": "CNPERP",
        "extract_paths": {
            "windows": "C:\\CNPERP",
            "linux": "/opt/CNPERP",
            "mac": "~/CNPERP",
        },
        "cloud_sync": {
            "enabled_by_default": True,
            "realtime": True,
            "description": "LAN sales, invoices, and journals push to the online hub within seconds after each save.",
        },
        "steps": [
            "Download the ZIP — it contains a CNPERP folder",
            "Extract: Windows → C:\\CNPERP · Linux → /opt/CNPERP · Mac → ~/CNPERP",
            "Run the installer for your OS (see platform guide below)",
            "Start the server — serves your LAN on port 8010",
            "Open /setup — license key, company setup, cloud mirror created automatically",
        ],
        "downloads": _installer_files(),
        "requirements": {
            "os": "Windows 10+, Ubuntu 22.04+, or macOS 12+",
            "python": "3.10+",
            "database": "PostgreSQL 14+",
            "ram_gb": 4,
            "disk_gb": 10,
        },
    }


@router.get("/download/package")
def download_full_package(
    request: Request,
    rebuild: bool = Query(False, description="Force rebuild ZIP cache"),
):
    """One-click download: full CNPERP local server package (ZIP)."""
    _require_installer_key(request)
    try:
        filename, path = get_package_path(force_rebuild=rebuild)
    except Exception as exc:
        raise HTTPException(status_code=500, detail=f"Could not build install package: {exc}") from exc

    if not path.is_file():
        raise HTTPException(status_code=404, detail="Install package not found")

    return FileResponse(
        str(path),
        media_type="application/zip",
        filename=filename,
        headers={"Content-Disposition": f'attachment; filename="{filename}"'},
    )


@router.get("/download/{filename}")
def download_installer_file(filename: str, request: Request):
    """Serve installer scripts from deploy/local-server/."""
    _require_installer_key(request)
    allowed = {
        "Install-CNPERP-Local.ps1",
        "Start-CNPERP-Server.ps1",
        "Connect-Cloud.ps1",
        "install-cnperp-local.sh",
        "start-cnperp-server.sh",
        "connect-cloud.sh",
        "setup_license_heartbeat_cron.sh",
        "cnperp-local.service.template",
        "local-install.env.template",
    }
    if filename not in allowed:
        raise HTTPException(status_code=404, detail="File not found")

    path = os.path.join(_LOCAL_SERVER_DIR, filename)
    if not os.path.isfile(path):
        raise HTTPException(status_code=404, detail="Installer file missing on server")

    media = "application/octet-stream"
    if filename.endswith(".ps1") or filename.endswith(".sh"):
        media = "text/plain; charset=utf-8"

    return FileResponse(
        path,
        media_type=media,
        filename=filename,
        headers={"Content-Disposition": f'attachment; filename="{filename}"'},
    )
