import os
from pathlib import Path
from typing import List, Optional
import asyncio
from concurrent.futures import ThreadPoolExecutor

from fastapi import FastAPI, HTTPException, BackgroundTasks
from pydantic import BaseModel
import uvicorn

app = FastAPI(title="BIN to JPEG/PDF Converter")

# Thread pool for CPU-intensive operations
executor = ThreadPoolExecutor(max_workers=4)


class ConversionResult(BaseModel):
    bin_file: str
    jpeg_file: Optional[str] = None
    pdf_file: Optional[str] = None
    status: str
    error: Optional[str] = None


class ConversionResponse(BaseModel):
    total_found: int
    successful: int
    failed: int
    results: List[ConversionResult]


def is_jpeg_file(file_path: str) -> bool:
    """Check if file is a JPEG file by reading header"""
    try:
        with open(file_path, 'rb') as f:
            header = f.read(11)
            # JPEG file signature: FF D8 FF
            return header[:3] == b'\xff\xd8\xff'
    except Exception:
        return False


def convert_bin_to_jpeg(bin_path: str, jpeg_path: str) -> bool:
    """Convert bin file to JPEG using sips command"""
    try:
        import subprocess
        result = subprocess.run(
            ['sips', '-s', 'format', 'jpeg', bin_path, '--out', jpeg_path],
            capture_output=True,
            text=True,
            timeout=30
        )
        return result.returncode == 0
    except Exception as e:
        print(f"Error converting to JPEG: {e}")
        return False


def convert_bin_to_pdf(bin_path: str, pdf_path: str) -> bool:
    """Convert bin file to PDF using sips command"""
    try:
        import subprocess
        # Convert directly from bin to PDF
        result = subprocess.run(
            ['sips', '-s', 'format', 'pdf', bin_path, '--out', pdf_path],
            capture_output=True,
            text=True,
            timeout=30
        )
        return result.returncode == 0
    except Exception as e:
        print(f"Error converting to PDF: {e}")
        return False


def convert_single_file(bin_path: str) -> ConversionResult:
    """Convert a single .bin file to JPEG and PDF"""
    bin_file = Path(bin_path)
    jpeg_path = bin_file.with_suffix('.jpg')
    pdf_path = bin_file.with_suffix('.pdf')
    
    result = ConversionResult(
        bin_file=str(bin_file),
        status="processing"
    )
    
    # Check if file is a JPEG
    if not is_jpeg_file(bin_path):
        result.status = "failed"
        result.error = "File is not a valid JPEG file"
        return result
    
    # Convert .bin to JPEG
    jpeg_success = convert_bin_to_jpeg(bin_path, str(jpeg_path))
    if jpeg_success:
        result.jpeg_file = str(jpeg_path)
    else:
        result.error = "Failed to convert .bin to JPEG"
        result.status = "failed"
        return result
    
    # Convert .bin to PDF (directly from .bin, not from .jpg)
    pdf_success = convert_bin_to_pdf(bin_path, str(pdf_path))
    if pdf_success:
        result.pdf_file = str(pdf_path)
    
    result.status = "completed"
    return result


def find_bin_files(root_dir: str) -> List[str]:
    """Find all .bin files in directory and subdirectories"""
    bin_files = []
    for root, dirs, files in os.walk(root_dir):
        for file in files:
            if file.endswith('.bin'):
                bin_files.append(os.path.join(root, file))
    return bin_files


@app.get("/")
async def root():
    """Root endpoint"""
    return {
        "message": "BIN to JPEG/PDF Converter API",
        "endpoints": {
            "convert_all": "POST /convert/all?root_dir=<path>",
            "convert_single": "POST /convert/single?file_path=<path>"
        }
    }


@app.post("/convert/all", response_model=ConversionResponse)
async def convert_all(root_dir: Optional[str] = None):
    """
    Convert all .bin files in a directory tree to JPEG and PDF
    """
    if root_dir is None:
        root_dir = os.getcwd()
    
    if not os.path.isdir(root_dir):
        raise HTTPException(status_code=400, detail=f"Directory not found: {root_dir}")
    
    # Find all .bin files
    bin_files = find_bin_files(root_dir)
    
    if not bin_files:
        return ConversionResponse(
            total_found=0,
            successful=0,
            failed=0,
            results=[]
        )
    
    # Convert files using thread pool
    loop = asyncio.get_event_loop()
    tasks = [loop.run_in_executor(executor, convert_single_file, bin_file) 
             for bin_file in bin_files]
    
    results = await asyncio.gather(*tasks)
    
    successful = sum(1 for r in results if r.status == "completed")
    failed = len(results) - successful
    
    return ConversionResponse(
        total_found=len(bin_files),
        successful=successful,
        failed=failed,
        results=results
    )


@app.post("/convert/single", response_model=ConversionResult)
async def convert_single(file_path: str):
    """
    Convert a single .bin file to JPEG and PDF
    """
    if not os.path.isfile(file_path):
        raise HTTPException(status_code=404, detail=f"File not found: {file_path}")
    
    if not file_path.endswith('.bin'):
        raise HTTPException(status_code=400, detail="File must have .bin extension")
    
    loop = asyncio.get_event_loop()
    result = await loop.run_in_executor(executor, convert_single_file, file_path)
    
    return result


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)
