"""
Capture Upload Endpoints

Handles .sub file uploads with GPS manifests
"""

from typing import List
from fastapi import APIRouter, UploadFile, File, Form, Depends, HTTPException, status
from sqlalchemy.orm import Session
from loguru import logger
import hashlib
import json
from datetime import datetime

from src.api.dependencies import get_db, optional_auth, get_storage
from src.database.models import User, Capture, Session as CaptureSession
from src.parser.sub_parser import parse_sub_file
from src.gps.validator import validate_gps_coordinates
from config.settings import settings


router = APIRouter()


# =============================================================================
# UPLOAD ENDPOINT
# =============================================================================

@router.post("/captures/upload")
async def upload_captures(
    manifest: str = Form(..., description="JSON manifest with GPS data"),
    files: List[UploadFile] = File(..., description=".sub files to upload"),
    db: Session = Depends(get_db),
    user: User = Depends(optional_auth),
    storage = Depends(get_storage)
):
    """
    Upload RF captures with GPS coordinates

    **Manifest Format** (JSON):
    ```json
    {
        "session_uuid": "550e8400-e29b-41d4-a716-446655440000",
        "captures": [
            {
                "filename": "capture_001.sub",
                "latitude": 40.7128,
                "longitude": -74.0060,
                "accuracy": 5.0,
                "altitude": 10.5,
                "timestamp": "2026-01-12T10:00:00Z"
            }
        ]
    }
    ```

    **Process**:
    1. Parse and validate manifest
    2. Compute SHA256 hash for each file (deduplication)
    3. Validate GPS coordinates
    4. Parse .sub file metadata
    5. Store file in storage backend
    6. Save capture to database
    7. Return upload summary

    Returns:
        Upload summary with processed captures
    """

    try:
        # Parse manifest
        manifest_data = json.loads(manifest)

        # Extract session UUID
        session_uuid = manifest_data.get("session_uuid")
        captures_manifest = manifest_data.get("captures", [])

        logger.info(f"Upload request: {len(files)} files, session={session_uuid}")

        # Get or create session
        capture_session = None
        if session_uuid:
            capture_session = db.query(CaptureSession).filter_by(
                session_uuid=session_uuid
            ).first()

            if not capture_session:
                # Create new session
                capture_session = CaptureSession(
                    session_uuid=session_uuid,
                    user_id=user.id if user else None,
                    started_at=datetime.utcnow()
                )
                db.add(capture_session)
                db.flush()  # Get session ID

        # Process files
        results = []
        errors = []

        # Create filename to manifest mapping
        manifest_map = {c['filename']: c for c in captures_manifest}

        for file in files:
            try:
                # Read file content
                content = await file.read()

                # Compute SHA256 hash
                file_hash = hashlib.sha256(content).hexdigest()

                # Check if already exists (deduplication)
                existing = db.query(Capture).filter_by(file_hash=file_hash).first()
                if existing:
                    results.append({
                        "filename": file.filename,
                        "status": "duplicate",
                        "file_hash": file_hash
                    })
                    continue

                # Get manifest entry for this file
                manifest_entry = manifest_map.get(file.filename)
                if not manifest_entry:
                    errors.append({
                        "filename": file.filename,
                        "error": "Missing manifest entry"
                    })
                    continue

                # Validate GPS coordinates
                latitude = float(manifest_entry['latitude'])
                longitude = float(manifest_entry['longitude'])
                accuracy = manifest_entry.get('accuracy')

                if not validate_gps_coordinates(latitude, longitude, accuracy):
                    errors.append({
                        "filename": file.filename,
                        "error": f"Invalid GPS coordinates: ({latitude}, {longitude})"
                    })
                    continue

                # Parse .sub file
                # Save content temporarily to parse
                import tempfile
                with tempfile.NamedTemporaryFile(delete=False, suffix='.sub') as tmp:
                    tmp.write(content)
                    tmp_path = tmp.name

                try:
                    metadata = parse_sub_file(tmp_path)
                except Exception as e:
                    errors.append({
                        "filename": file.filename,
                        "error": f"Failed to parse .sub file: {e}"
                    })
                    continue
                finally:
                    import os
                    os.unlink(tmp_path)

                # Store file in storage backend
                storage_path = storage.save_file(
                    file_hash=file_hash,
                    content=content,
                    filename=file.filename
                )

                # Create capture record
                capture = Capture(
                    file_hash=file_hash,
                    session_id=capture_session.id if capture_session else None,
                    user_id=user.id if user else None,
                    latitude=latitude,
                    longitude=longitude,
                    altitude=manifest_entry.get('altitude'),
                    gps_accuracy=accuracy,
                    captured_at=datetime.fromisoformat(
                        manifest_entry['timestamp'].replace('Z', '+00:00')
                    ),
                    frequency=metadata.frequency,
                    rssi=None,  # Not in .sub file typically
                    modulation=metadata.modulation,
                    preset=metadata.preset,
                    protocol=metadata.protocol,
                    bit_length=metadata.bit_length,
                    key_data=metadata.key_data,
                    timing_element=metadata.timing_element,
                    raw_data=str(metadata.raw_data) if metadata.raw_data else None,
                    raw_format=metadata.file_format,
                    file_path=storage_path,
                    file_size=len(content)
                )

                db.add(capture)

                results.append({
                    "filename": file.filename,
                    "status": "uploaded",
                    "file_hash": file_hash,
                    "frequency": metadata.frequency,
                    "protocol": metadata.protocol
                })

                logger.debug(f"Capture uploaded: {file.filename} -> {file_hash}")

            except Exception as e:
                logger.error(f"Failed to process file {file.filename}: {e}")
                errors.append({
                    "filename": file.filename,
                    "error": str(e)
                })

        # Commit all captures
        db.commit()

        logger.success(f"Upload complete: {len(results)} processed, {len(errors)} errors")

        return {
            "session_uuid": session_uuid,
            "uploaded": len([r for r in results if r['status'] == 'uploaded']),
            "duplicates": len([r for r in results if r['status'] == 'duplicate']),
            "errors": len(errors),
            "results": results,
            "error_details": errors if errors else None
        }

    except json.JSONDecodeError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Invalid JSON manifest: {e}"
        )
    except Exception as e:
        logger.error(f"Upload failed: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Upload failed: {e}"
        )


# =============================================================================
# CAPTURE QUERY ENDPOINT
# =============================================================================

@router.get("/captures/{file_hash}")
async def get_capture(
    file_hash: str,
    db: Session = Depends(get_db)
):
    """
    Get capture details by file hash

    Args:
        file_hash: SHA256 hash of capture file

    Returns:
        Capture details including metadata and device match
    """
    capture = db.query(Capture).filter_by(file_hash=file_hash).first()

    if not capture:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Capture not found: {file_hash}"
        )

    return capture.to_dict()
