from fastapi import FastAPI, Depends, HTTPException, UploadFile, File, BackgroundTasks, Body
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.orm import Session, joinedload
from typing import List, Dict, Any
import os
import shutil
import uuid
from datetime import datetime

from .config import settings
from .database import init_db, get_db, Meeting, TranscriptChunk, AnalysisResult, SessionLocal
from .services.orchestrator import process_meeting_task
from .services.insights_service import generate_insight

# Initialize FastAPI App
app = FastAPI(
    title=settings.APP_NAME,
    version=settings.VERSION,
    root_path="/tr"
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.on_event("startup")
def startup_event():
    init_db()

@app.get("/api/health")
def health():
    return {"status": "ok", "version": settings.VERSION}

@app.get("/api/meetings")
def list_meetings(db: Session = Depends(get_db)):
    return db.query(Meeting).order_by(Meeting.created_at.desc()).all()

@app.get("/api/meetings/{meeting_id}")
def get_meeting(meeting_id: int, db: Session = Depends(get_db)):
    meeting = db.query(Meeting).options(
        joinedload(Meeting.chunks),
        joinedload(Meeting.analysis_results) # Eager load analysis results
    ).filter(Meeting.id == meeting_id).first()
    
    if not meeting:
        raise HTTPException(404, detail="Meeting not found")
    
    # Sort chunks by index
    meeting.chunks.sort(key=lambda x: x.chunk_index)
    
    return meeting

@app.put("/api/chunks/{chunk_id}")
def update_chunk(chunk_id: int, payload: Dict[str, Any] = Body(...), db: Session = Depends(get_db)):
    chunk = db.query(TranscriptChunk).filter(TranscriptChunk.id == chunk_id).first()
    if not chunk:
        raise HTTPException(404, detail="Chunk not found")
    
    # Update JSON content (e.g. after editing/deleting lines)
    if "json_content" in payload:
        chunk.json_content = payload["json_content"]
        db.commit()
    
    return {"status": "updated"}

@app.post("/api/upload")
async def upload_audio(
    background_tasks: BackgroundTasks,
    file: UploadFile = File(...),
    db: Session = Depends(get_db)
):
    # 1. Save File
    file_id = str(uuid.uuid4())
    ext = os.path.splitext(file.filename)[1]
    filename = f"{file_id}{ext}"
    file_path = os.path.join(settings.UPLOAD_DIR, filename)
    
    with open(file_path, "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)
    
    # 2. Create DB Entry
    meeting = Meeting(
        title=file.filename,
        filename=filename,
        file_path=file_path,
        status="UPLOADED"
    )
    db.add(meeting)
    db.commit()
    db.refresh(meeting)
    
    # 3. Trigger Processing in Background
    background_tasks.add_task(process_meeting_task, meeting.id, SessionLocal)
    
    return meeting

@app.post("/api/meetings/{meeting_id}/retry")
def retry_meeting(
    meeting_id: int,
    background_tasks: BackgroundTasks,
    db: Session = Depends(get_db)
):
    meeting = db.query(Meeting).filter(Meeting.id == meeting_id).first()
    if not meeting:
        raise HTTPException(404, detail="Meeting not found")
    
    # Check if chunks directory exists
    chunk_dir = os.path.join(settings.UPLOAD_DIR, "chunks", str(meeting_id))
    if not os.path.exists(chunk_dir) or not os.listdir(chunk_dir):
         raise HTTPException(400, detail="Original audio chunks not found. Please re-upload.")

    # Reset status
    meeting.status = "QUEUED"
    db.commit()

    # Trigger Retry Task
    from .services.orchestrator import retry_meeting_task
    background_tasks.add_task(retry_meeting_task, meeting.id, SessionLocal)
    
    return {"status": "started", "message": "Retrying transcription..."}

from pydantic import BaseModel

class InsightRequest(BaseModel):
    insight_type: str

@app.post("/api/meetings/{meeting_id}/insights")
def create_insight(meeting_id: int, payload: InsightRequest, db: Session = Depends(get_db)):
    """
    Triggers the generation of a specific insight (e.g., meeting minutes, action items).
    If the insight already exists, it returns the stored result.
    Otherwise, it generates, stores, and returns the new insight.
    """
    try:
        insight = generate_insight(db, meeting_id, payload.insight_type)
        return insight
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        # For unexpected errors, return a generic 500 error
        print(f"ERROR: Unexpected error in create_insight: {e}")
        raise HTTPException(status_code=500, detail="An internal error occurred while generating the insight.")

class TranslationRequest(BaseModel):
    target_language: str

@app.post("/api/meetings/{meeting_id}/translate")
def translate_meeting_transcript(meeting_id: int, payload: TranslationRequest, db: Session = Depends(get_db)):
    """
    Triggers the translation of a meeting's transcript.
    """
    try:
        # For now, we only support English
        if payload.target_language.lower() != 'english':
            raise HTTPException(status_code=400, detail="Currently, only translation to English is supported.")

        from .services.translation_service import translate_transcript
        translation = translate_transcript(db, meeting_id, payload.target_language)
        return translation
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        print(f"ERROR: Unexpected error in translate_meeting_transcript: {e}")
        raise HTTPException(status_code=500, detail="An internal error occurred during translation.")

class RenameRequest(BaseModel):
    old_name: str
    new_name: str

@app.post("/api/meetings/{meeting_id}/rename_speaker")
def rename_speaker_globally(meeting_id: int, payload: RenameRequest, db: Session = Depends(get_db)):
    meeting = db.query(Meeting).filter(Meeting.id == meeting_id).first()
    if not meeting:
        raise HTTPException(404, detail="Meeting not found")
    
    count = 0
    # Iterate over all chunks directly from DB relation
    for chunk in meeting.chunks:
        if not chunk.json_content:
            continue
            
        modified = False
        new_content = []
        for msg in chunk.json_content:
            if msg.get("speaker") == payload.old_name:
                msg["speaker"] = payload.new_name
                modified = True
                count += 1
            new_content.append(msg)
        
        if modified:
            # Force update of the JSON field
            chunk.json_content = list(new_content)
            db.add(chunk)
            
    db.commit()
    return {"status": "updated", "rows_affected": count}

@app.delete("/api/meetings/{meeting_id}")
def delete_meeting(meeting_id: int, db: Session = Depends(get_db)):
    meeting = db.query(Meeting).filter(Meeting.id == meeting_id).first()
    if not meeting:
        raise HTTPException(404, detail="Meeting not found")
    
    # 1. Delete Files
    try:
        if os.path.exists(meeting.file_path):
            os.remove(meeting.file_path)
        
        # Delete chunks dir
        chunk_dir = os.path.join(settings.UPLOAD_DIR, "chunks", str(meeting_id))
        if os.path.exists(chunk_dir):
            shutil.rmtree(chunk_dir)
    except Exception as e:
        print(f"Error deleting files: {e}")

    # 2. Delete DB Entry (Cascade deletes chunks/analyses)
    db.delete(meeting)
    db.commit()
    return {"status": "deleted"}

# Serve Frontend
# This must be the last route definition to avoid catching API routes

# PRIORITY 1: Mounted Volume (Development / Live Update)
static_path = "/app/frontend/dist"

# PRIORITY 2: Built-in Image Path (Production)
if not os.path.exists(static_path):
    static_path = "/frontend_static"

# PRIORITY 3: Local Development (running python directly)
if not os.path.exists(static_path):
    static_path = os.path.join(os.path.dirname(__file__), "../frontend/dist")

if os.path.exists(static_path):
    app.mount("/", StaticFiles(directory=static_path, html=True), name="static")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("backend.app:app", host="0.0.0.0", port=8001, reload=True)
