"""
모바일 앱 직접 배포 — QR 코드 기반

APK 업로드 → QR 자동 생성 → 랜딩 페이지 → 앱스토어 없이 설치.
공공기관 내부망 배포에 최적화.

엔드포인트:
  POST /api/app/upload          — APK 파일 업로드 + QR 생성
  POST /api/app/url             — 외부 URL(EAS 등)로 QR 생성
  GET  /api/app/latest          — 최신 버전 정보 + QR URL
  GET  /api/app/qr              — QR 코드 이미지 (PNG)
  GET  /api/app/landing         — 앱 다운로드 랜딩 페이지 (HTML)
  GET  /api/app/download        — APK 파일 다운로드
  GET  /api/app/versions        — 버전 이력
  DELETE /api/app/versions/{id} — 구버전 삭제
  GET  /api/app/stats           — 다운로드 통계
"""
from __future__ import annotations

import base64
import io
import logging
import os
import uuid
from datetime import datetime
from pathlib import Path
from typing import Optional

from fastapi import APIRouter, Depends, File, Form, HTTPException, Request, UploadFile
from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse, Response
from pydantic import BaseModel
from sqlalchemy import select, desc, func
from sqlalchemy.ext.asyncio import AsyncSession

from core.auth import get_current_user, require_admin_role
from database import get_db
from models import User, AppVersion, AppDownloadLog

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/app", tags=["앱 배포"])

APK_DIR = Path("/opt/guardia/app/uploads/apk")
APK_DIR.mkdir(parents=True, exist_ok=True)

BASE_URL = "https://zioinfo.co.kr:8443"  # 랜딩 페이지 베이스 URL


def _generate_qr(url: str) -> bytes:
    """QR 코드 PNG 생성."""
    try:
        import qrcode
        from qrcode.image.styledpil import StyledPilImage
        qr = qrcode.QRCode(version=1, box_size=10, border=4)
        qr.add_data(url)
        qr.make(fit=True)
        img = qr.make_image(fill_color="#003366", back_color="white")
        buf = io.BytesIO()
        img.save(buf, format='PNG')
        return buf.getvalue()
    except ImportError:
        # qrcode 미설치 시 빈 1x1 PNG 반환 + 경고
        logger.warning("qrcode 라이브러리 미설치. `pip install qrcode[pil]` 실행 필요.")
        # 최소 PNG (1x1 흰 픽셀)
        min_png = base64.b64decode(
            "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="
        )
        return min_png


class UrlRequest(BaseModel):
    android_url: str
    ios_url: Optional[str] = None
    version: str = "latest"
    release_notes: Optional[str] = None


@router.post("/upload")
async def upload_apk(
    file: UploadFile = File(...),
    version: str = Form(..., description="버전 (예: 1.2.3)"),
    release_notes: str = Form("", description="업데이트 내용"),
    ios_url: str = Form("", description="iOS TestFlight URL"),
    db: AsyncSession = Depends(get_db),
    user: User = Depends(require_admin_role),
):
    """APK 파일 업로드 → QR 코드 자동 생성."""
    if not file.filename or not file.filename.endswith('.apk'):
        raise HTTPException(400, "APK 파일만 업로드 가능합니다 (.apk)")

    file_bytes = await file.read()
    if len(file_bytes) > 200 * 1024 * 1024:  # 200MB
        raise HTTPException(413, "파일 크기 초과 (최대 200MB)")

    # 고유 파일명으로 저장
    filename = f"guardia_messenger_{version}_{uuid.uuid4().hex[:8]}.apk"
    file_path = APK_DIR / filename
    file_path.write_bytes(file_bytes)

    # 기존 latest 해제
    from sqlalchemy import update as sa_update
    await db.execute(
        sa_update(AppVersion)
        .where(AppVersion.is_latest == True)
        .values(is_latest=False)
    )

    # 랜딩 페이지 URL → QR
    token = uuid.uuid4().hex
    landing_url = f"{BASE_URL}/api/app/landing?token={token}"
    qr_bytes = _generate_qr(landing_url)
    qr_b64 = base64.b64encode(qr_bytes).decode()

    app_ver = AppVersion(
        version=version,
        platform="ANDROID",
        file_path=str(file_path),
        file_size_mb=round(len(file_bytes) / 1024 / 1024, 2),
        android_url=f"{BASE_URL}/api/app/download?token={token}",
        ios_url=ios_url or None,
        landing_token=token,
        qr_data=qr_b64,
        release_notes=release_notes,
        download_count=0,
        is_latest=True,
        uploaded_by=user.id,
        created_at=datetime.utcnow(),
    )
    db.add(app_ver)
    await db.commit()
    await db.refresh(app_ver)

    return {
        "ok": True,
        "version_id": app_ver.id,
        "version": version,
        "qr_url": f"{BASE_URL}/api/app/qr?token={token}",
        "landing_url": landing_url,
        "download_url": app_ver.android_url,
        "file_size_mb": round(len(file_bytes) / 1024 / 1024, 1),
    }


@router.post("/url")
async def set_app_url(
    req: UrlRequest,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(require_admin_role),
):
    """외부 URL(EAS 빌드 등)로 QR 코드 생성."""
    from sqlalchemy import update as sa_update
    await db.execute(
        sa_update(AppVersion)
        .where(AppVersion.is_latest == True)
        .values(is_latest=False)
    )

    token = uuid.uuid4().hex
    landing_url = f"{BASE_URL}/api/app/landing?token={token}"
    qr_bytes = _generate_qr(landing_url)

    app_ver = AppVersion(
        version=req.version,
        platform="BOTH" if req.ios_url else "ANDROID",
        android_url=req.android_url,
        ios_url=req.ios_url,
        landing_token=token,
        qr_data=base64.b64encode(qr_bytes).decode(),
        release_notes=req.release_notes,
        download_count=0,
        is_latest=True,
        uploaded_by=user.id,
        created_at=datetime.utcnow(),
    )
    db.add(app_ver)
    await db.commit()
    await db.refresh(app_ver)

    return {
        "ok": True,
        "version_id": app_ver.id,
        "qr_url": f"{BASE_URL}/api/app/qr?token={token}",
        "landing_url": landing_url,
    }


@router.get("/latest")
async def get_latest(
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_current_user),
):
    """최신 버전 정보 조회."""
    row = await db.execute(
        select(AppVersion).where(AppVersion.is_latest == True)
    )
    ver = row.scalar_one_or_none()
    if not ver:
        return {"has_version": False}
    return {
        "has_version": True,
        "version": ver.version,
        "platform": ver.platform,
        "download_count": ver.download_count,
        "qr_url": f"{BASE_URL}/api/app/qr?token={ver.landing_token}",
        "landing_url": f"{BASE_URL}/api/app/landing?token={ver.landing_token}",
        "release_notes": ver.release_notes,
        "created_at": ver.created_at,
    }


@router.get("/qr")
async def get_qr_image(
    token: str,
    db: AsyncSession = Depends(get_db),
):
    """QR 코드 이미지 반환 (PNG). 인증 불필요 — 공유 가능."""
    row = await db.execute(
        select(AppVersion).where(AppVersion.landing_token == token)
    )
    ver = row.scalar_one_or_none()
    if not ver or not ver.qr_data:
        raise HTTPException(404, "QR 코드 없음")
    img_bytes = base64.b64decode(ver.qr_data)
    return Response(content=img_bytes, media_type="image/png",
                    headers={"Cache-Control": "public, max-age=3600"})


@router.get("/landing", response_class=HTMLResponse)
async def app_landing(
    token: str,
    request: Request,
    db: AsyncSession = Depends(get_db),
):
    """앱 다운로드 랜딩 페이지 (사용자가 QR 스캔 시 보는 화면). 인증 불필요."""
    row = await db.execute(
        select(AppVersion).where(AppVersion.landing_token == token)
    )
    ver = row.scalar_one_or_none()
    if not ver:
        return HTMLResponse("<h1>잘못된 QR 코드입니다</h1>", status_code=404)

    # User-Agent로 플랫폼 감지
    ua = request.headers.get("User-Agent", "").lower()
    is_ios = "iphone" in ua or "ipad" in ua

    android_btn = ""
    ios_btn = ""
    if ver.android_url:
        android_btn = f'<a href="{ver.android_url}" class="btn android-btn">📱 Android 다운로드 (APK)</a>'
    if ver.ios_url:
        ios_btn = f'<a href="{ver.ios_url}" class="btn ios-btn">🍎 iOS (TestFlight)</a>'

    html = f"""<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GUARDiA Messenger 다운로드</title>
<style>
  * {{ box-sizing: border-box; margin: 0; padding: 0 }}
  body {{ font-family: 'Pretendard', -apple-system, sans-serif; background: #f0f4ff; min-height: 100vh; display: flex; align-items: center; justify-content: center }}
  .card {{ background: #fff; border-radius: 20px; padding: 40px 32px; max-width: 400px; width: 90%; text-align: center; box-shadow: 0 8px 32px rgba(0,51,102,.12) }}
  .logo {{ font-size: 48px; margin-bottom: 16px }}
  h1 {{ color: #003366; font-size: 24px; font-weight: 800; margin-bottom: 8px }}
  .version {{ color: #64748b; font-size: 14px; margin-bottom: 24px }}
  .btn {{ display: block; padding: 14px 24px; border-radius: 12px; font-size: 16px; font-weight: 700; text-decoration: none; margin-bottom: 12px; transition: transform .1s }}
  .btn:active {{ transform: scale(0.98) }}
  .android-btn {{ background: #003366; color: #fff }}
  .ios-btn {{ background: #1d1d1f; color: #fff }}
  .guide {{ background: #f8fafc; border-radius: 10px; padding: 16px; margin-top: 20px; text-align: left; font-size: 13px; color: #475569 }}
  .guide h3 {{ font-size: 13px; font-weight: 700; margin-bottom: 8px; color: #003366 }}
  .guide li {{ margin-left: 16px; margin-bottom: 4px }}
  .notes {{ margin-top: 16px; font-size: 13px; color: #64748b; line-height: 1.6 }}
</style>
</head>
<body>
<div class="card">
  <div class="logo">🛡️</div>
  <h1>GUARDiA Messenger</h1>
  <div class="version">버전 {ver.version}</div>
  {'<div style="background:#fef3c7;border-radius:8px;padding:10px;margin-bottom:16px;font-size:13px;color:#92400e">📱 iOS 기기가 감지되었습니다</div>' if is_ios else ''}
  {android_btn}
  {ios_btn}
  {'<p style="color:#ef4444;font-size:13px;margin-top:8px">⚠️ 버전 정보가 없습니다</p>' if not ver.android_url and not ver.ios_url else ''}
  {f'<div class="notes">{ver.release_notes}</div>' if ver.release_notes else ''}
  <div class="guide">
    <h3>📋 Android 설치 가이드</h3>
    <ol>
      <li>위 "Android 다운로드" 클릭</li>
      <li>APK 파일 다운로드 완료 대기</li>
      <li>설정 → 보안 → "알 수 없는 소스" 허용</li>
      <li>다운로드된 APK 파일 실행 → 설치</li>
    </ol>
  </div>
</div>
</body>
</html>"""

    # 다운로드 로그
    log = AppDownloadLog(
        version_id=ver.id,
        platform="IOS" if is_ios else "ANDROID",
        user_agent=request.headers.get("User-Agent", "")[:200],
        downloaded_at=datetime.utcnow(),
    )
    db.add(log)
    await db.commit()

    return HTMLResponse(content=html)


@router.get("/download")
async def download_apk(
    token: str,
    db: AsyncSession = Depends(get_db),
):
    """APK 파일 다운로드. 인증 불필요."""
    row = await db.execute(
        select(AppVersion).where(AppVersion.landing_token == token)
    )
    ver = row.scalar_one_or_none()
    if not ver or not ver.file_path:
        raise HTTPException(404, "파일 없음")
    if not Path(ver.file_path).exists():
        raise HTTPException(404, "APK 파일이 서버에 없습니다")

    ver.download_count = (ver.download_count or 0) + 1
    await db.commit()

    return FileResponse(
        ver.file_path,
        filename=f"guardia_messenger_{ver.version}.apk",
        media_type="application/vnd.android.package-archive",
    )


@router.get("/versions")
async def list_versions(
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_current_user),
):
    rows = await db.execute(
        select(AppVersion).order_by(desc(AppVersion.created_at)).limit(20)
    )
    versions = rows.scalars().all()
    return [
        {
            "id": v.id, "version": v.version, "platform": v.platform,
            "download_count": v.download_count, "is_latest": v.is_latest,
            "qr_url": f"{BASE_URL}/api/app/qr?token={v.landing_token}",
            "landing_url": f"{BASE_URL}/api/app/landing?token={v.landing_token}",
            "file_size_mb": round((v.file_size_mb or 0), 1),
            "release_notes": v.release_notes,
            "created_at": v.created_at,
        }
        for v in versions
    ]


@router.delete("/versions/{version_id}")
async def delete_version(
    version_id: int,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(require_admin_role),
):
    row = await db.execute(
        select(AppVersion).where(AppVersion.id == version_id)
    )
    ver = row.scalar_one_or_none()
    if not ver:
        raise HTTPException(404)
    if ver.is_latest:
        raise HTTPException(400, "최신 버전은 삭제 불가. 새 버전 업로드 후 삭제하세요.")
    if ver.file_path and Path(ver.file_path).exists():
        Path(ver.file_path).unlink()
    await db.delete(ver)
    await db.commit()
    return {"ok": True}


@router.get("/stats")
async def app_stats(
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_current_user),
):
    total = (await db.execute(
        select(func.sum(AppVersion.download_count))
    )).scalar() or 0
    android = (await db.execute(
        select(func.count(AppDownloadLog.id)).where(AppDownloadLog.platform == "ANDROID")
    )).scalar() or 0
    ios = (await db.execute(
        select(func.count(AppDownloadLog.id)).where(AppDownloadLog.platform == "IOS")
    )).scalar() or 0
    return {"total_downloads": total, "android": android, "ios": ios}
