"""
Public (no-auth) endpoints for CloudFlash and feature gate checks.
"""
from fastapi import APIRouter, HTTPException
from fastapi.responses import Response
from pydantic import BaseModel
from typing import List, Optional

from settings.public_features_service import get_public_features
from firmware.service import list_firmware
from utils.nvs_generator import generate as generate_nvs
from manufacturing.service import get_device_by_sn
from shared.exceptions import NotFoundError

router = APIRouter(prefix="/api/public", tags=["public"])


# ── Feature gate ──────────────────────────────────────────────────────────────

class CloudFlashStatus(BaseModel):
    enabled: bool


@router.get("/cloudflash/status", response_model=CloudFlashStatus)
async def cloudflash_status():
    """Returns whether the CloudFlash public page is currently enabled."""
    settings = get_public_features()
    return CloudFlashStatus(enabled=settings.cloudflash_enabled)


def _require_cloudflash_enabled():
    """Raises 403 if CloudFlash is disabled."""
    settings = get_public_features()
    if not settings.cloudflash_enabled:
        raise HTTPException(status_code=403, detail="CloudFlash is currently disabled.")


# ── Public firmware list ───────────────────────────────────────────────────────

class PublicFirmwareOption(BaseModel):
    hw_type: str
    hw_type_label: str
    channel: str
    version: str
    download_url: str


HW_TYPE_LABELS = {
    "vesper":      "Vesper",
    "vesper_plus": "Vesper Plus",
    "vesper_pro":  "Vesper Pro",
    "agnus":       "Agnus",
    "agnus_mini":  "Agnus Mini",
    "chronos":     "Chronos",
    "chronos_pro": "Chronos Pro",
}


@router.get("/cloudflash/firmware", response_model=List[PublicFirmwareOption])
async def list_public_firmware():
    """
    Returns all available firmware options (is_latest=True, non-bespoke, stable channel only).
    No authentication required — used by the public CloudFlash page.
    """
    _require_cloudflash_enabled()

    all_fw = list_firmware()
    options = []
    for fw in all_fw:
        if not fw.is_latest:
            continue
        if fw.hw_type == "bespoke":
            continue
        if fw.channel != "stable":
            continue
        options.append(PublicFirmwareOption(
            hw_type=fw.hw_type,
            hw_type_label=HW_TYPE_LABELS.get(fw.hw_type, fw.hw_type.replace("_", " ").title()),
            channel=fw.channel,
            version=fw.version,
            download_url=f"/api/firmware/{fw.hw_type}/{fw.channel}/{fw.version}/firmware.bin",
        ))

    # Sort by hw_type label
    options.sort(key=lambda x: x.hw_type_label)
    return options


# ── Public serial number validation ──────────────────────────────────────────

class SerialValidationResult(BaseModel):
    valid: bool
    hw_type: Optional[str] = None
    hw_type_label: Optional[str] = None
    hw_version: Optional[str] = None


@router.get("/cloudflash/validate-serial/{serial_number}", response_model=SerialValidationResult)
async def validate_serial(serial_number: str):
    """
    Check whether a serial number exists in the device database.
    Returns hw_type info if found so the frontend can confirm it matches the user's selection.
    No sensitive device data is returned.
    """
    _require_cloudflash_enabled()

    sn = serial_number.strip().upper()
    try:
        device = get_device_by_sn(sn)
        return SerialValidationResult(
            valid=True,
            hw_type=device.hw_type,
            hw_type_label=HW_TYPE_LABELS.get(device.hw_type, device.hw_type.replace("_", " ").title()),
            hw_version=device.hw_version,
        )
    except Exception:
        return SerialValidationResult(valid=False)


# ── Public NVS generation ─────────────────────────────────────────────────────

class NvsRequest(BaseModel):
    serial_number: str
    hw_type: str
    hw_revision: str
    nvs_schema: str = "new"  # "legacy" | "new"

    @property
    def legacy(self) -> bool:
        return self.nvs_schema == "legacy"


@router.post("/cloudflash/nvs.bin")
async def generate_public_nvs(body: NvsRequest):
    """
    Generate an NVS binary for a given serial number + hardware info.
    No authentication required — used by the public CloudFlash page for Full Wipe flash.
    The serial number is provided by the user (they read it from the sticker on their device).
    """
    _require_cloudflash_enabled()

    sn = body.serial_number.strip().upper()
    if not sn:
        raise HTTPException(status_code=422, detail="Serial number is required.")

    hw_type = body.hw_type.strip().lower()
    hw_revision = body.hw_revision.strip()

    if not hw_type or not hw_revision:
        raise HTTPException(status_code=422, detail="hw_type and hw_revision are required.")

    try:
        nvs_bytes = generate_nvs(
            serial_number=sn,
            hw_family=hw_type,
            hw_revision=hw_revision,
            legacy=body.legacy,
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"NVS generation failed: {str(e)}")

    return Response(
        content=nvs_bytes,
        media_type="application/octet-stream",
        headers={"Content-Disposition": f'attachment; filename="{sn}_nvs.bin"'},
    )


# ── Public flash assets (bootloader + partitions) ─────────────────────────────

@router.get("/cloudflash/{hw_type}/bootloader.bin")
async def get_public_bootloader(hw_type: str):
    """
    Serve the bootloader binary for a given hw_type.
    No authentication required — used by the public CloudFlash page.
    """
    _require_cloudflash_enabled()

    import os
    from config import settings as cfg
    from pathlib import Path

    asset_path = Path(cfg.flash_assets_storage_path) / hw_type / "bootloader.bin"
    if not asset_path.exists():
        raise HTTPException(status_code=404, detail=f"Bootloader not found for {hw_type}.")

    return Response(
        content=asset_path.read_bytes(),
        media_type="application/octet-stream",
        headers={"Content-Disposition": f'attachment; filename="bootloader_{hw_type}.bin"'},
    )


@router.get("/cloudflash/{hw_type}/partitions.bin")
async def get_public_partitions(hw_type: str):
    """
    Serve the partition table binary for a given hw_type.
    No authentication required — used by the public CloudFlash page.
    """
    _require_cloudflash_enabled()

    import os
    from config import settings as cfg
    from pathlib import Path

    asset_path = Path(cfg.flash_assets_storage_path) / hw_type / "partitions.bin"
    if not asset_path.exists():
        raise HTTPException(status_code=404, detail=f"Partition table not found for {hw_type}.")

    return Response(
        content=asset_path.read_bytes(),
        media_type="application/octet-stream",
        headers={"Content-Disposition": f'attachment; filename="partitions_{hw_type}.bin"'},
    )
