"""Onboarding router — account setup wizard endpoints."""
from fastapi import APIRouter, Depends, File, UploadFile
from sqlalchemy.ext.asyncio import AsyncSession

from src.apps.onboarding.schemas.requests import OnboardingCompleteRequest
from src.apps.onboarding.services.onboarding_service import OnboardingService
from src.core.dependencies import get_current_user, require_tenant
from src.core.exceptions import ForbiddenError, ValidationError
from src.core.schemas.response import success
from src.database.session import get_db

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


@router.get("/status", response_model=dict)
async def get_onboarding_status(
    current_user=Depends(get_current_user),
    tenant_id: str = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
):
    """Return the current account status and onboarding completion timestamp.

    This endpoint is intentionally exempt from the require_onboarding_complete
    gate — it must be accessible to users who are still in the onboarding flow.
    """
    service = OnboardingService(db)
    data = await service.get_account_status(tenant_id)
    return success(data=data)


@router.patch("/complete", response_model=dict)
async def complete_onboarding(
    body: OnboardingCompleteRequest,
    current_user=Depends(get_current_user),
    tenant_id: str = Depends(require_tenant),
    db: AsyncSession = Depends(get_db),
):
    """Complete the onboarding wizard and activate the account.

    Sets account status to 'active' and persists branding configuration.
    Subsequent calls are idempotent — they return the current status without
    re-applying changes if the account is already active.

    Only users with the 'administrator' role may complete onboarding.
    """
    from src.core.constants import UserRole

    if current_user.role not in (UserRole.ADMINISTRATOR.value, UserRole.SITE_ADMIN.value):
        raise ForbiddenError("Only an administrator can complete onboarding")

    service = OnboardingService(db)
    data = await service.complete_onboarding(tenant_id, body)
    return success(data=data, message="Onboarding completed. Account is now active.")


@router.post("/logo", response_model=dict, status_code=201)
async def upload_onboarding_logo(
    logo: UploadFile = File(...),
    current_user=Depends(get_current_user),
    tenant_id: str = Depends(require_tenant),
):
    """Upload a logo during the onboarding wizard.

    This endpoint is intentionally exempt from the require_onboarding_complete
    gate — it must be accessible to users who are still in the onboarding flow.

    Accepts PNG, SVG, or JPEG files up to 2 MB and returns the S3 URL.
    """
    import io
    from src.core.config import settings
    from src.core.constants import UserRole

    if current_user.role not in (UserRole.ADMINISTRATOR.value, UserRole.SITE_ADMIN.value):
        raise ForbiddenError("Only an administrator can upload the logo during onboarding")

    allowed_mime = {"image/png", "image/svg+xml", "image/jpeg"}
    mime = logo.content_type or ""
    if mime not in allowed_mime:
        raise ValidationError("Only PNG, SVG, or JPEG files are allowed for the logo")

    content = await logo.read()
    if len(content) > 2 * 1024 * 1024:
        raise ValidationError("Logo must be under 2 MB")

    # Magic-byte verification for raster types to prevent MIME confusion attacks
    # (e.g. attacker renames a script file to .png and sets Content-Type: image/png).
    if mime == "image/png" and not content.startswith(b"\x89PNG"):
        raise ValidationError("File content does not match PNG format")
    if mime == "image/jpeg" and not content.startswith(b"\xff\xd8\xff"):
        raise ValidationError("File content does not match JPEG format")

    # SVG script-injection check — reject payloads embedding <script> or javascript: URIs
    if mime == "image/svg+xml":
        lower = content.lower()
        if any(pat in lower for pat in (b"<script", b"javascript:", b"data:text")):
            raise ValidationError("SVG file contains disallowed content (script or javascript URI)")

    import os
    import uuid as _uuid

    ext_map = {"image/png": "png", "image/svg+xml": "svg", "image/jpeg": "jpg"}
    ext = ext_map.get(mime, "png")
    key = f"tenants/{tenant_id}/logo/{_uuid.uuid4()}.{ext}"

    logo_url: str | None = None

    # Try S3 first
    try:
        import boto3

        s3 = boto3.client(
            "s3",
            region_name=settings.S3_DOCUMENTS_REGION,
            aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
            aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
        )
        s3.upload_fileobj(
            io.BytesIO(content),
            settings.S3_BUCKET,
            key,
            ExtraArgs={"ContentType": mime},
        )
        logo_url = f"{settings.CLOUDFRONT_URL}/{key}"
    except Exception as s3_exc:
        # S3 unavailable (bucket missing, no credentials) — fall back to local storage.
        # This is intentional in dev; production should always have a valid S3 bucket.
        import logging as _logging
        _logging.getLogger(__name__).warning(
            "S3 upload failed (%s) — falling back to local storage", s3_exc
        )
        try:
            uploads_root = os.path.join(
                os.path.dirname(__file__), "..", "..", "..", "uploads"
            )
            local_dir = os.path.join(uploads_root, "tenants", str(tenant_id), "logo")
            os.makedirs(local_dir, exist_ok=True)
            local_path = os.path.join(local_dir, f"{_uuid.uuid4()}.{ext}")
            with open(local_path, "wb") as fh:
                fh.write(content)
            # Return a URL served by the /uploads static mount in main.py
            rel = os.path.relpath(local_path, uploads_root).replace("\\", "/")
            scheme = "https" if settings.APP_ENV == "production" else "http"
            api_base = f"{scheme}://{settings.APP_DOMAIN}"
            logo_url = f"{api_base}/uploads/{rel}"
        except Exception as local_exc:
            raise ValidationError(f"Logo upload failed: {local_exc}") from local_exc

    return success(data={"logo_url": logo_url}, message="Logo uploaded")
