from fastapi import FastAPI, File, UploadFile, Form
from fastapi.responses import HTMLResponse, FileResponse
import whisper
import torch
import os
import srt
import logging
from datetime import timedelta
from time import time
from fpdf import FPDF
import uvicorn

logging.basicConfig(filename="speech_transcriber.log", level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)

device = "cuda" if torch.cuda.is_available() else "cpu"
app = FastAPI()

@app.get("/", response_class=HTMLResponse)
def home():
    return f"""
<!DOCTYPE html>
<html>
<head>
    <title>Trascrizione Audio/Video</title>
    <style>
        body {{
            background-color: #f5f7fa;
            font-family: 'Arial', sans-serif;
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100vh;
            margin: 0;
        }}
        .container {{
            background: #fff;
            padding: 30px;
            border-radius: 12px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.1);
            max-width: 500px;
            width: 90%;
        }}
        h1 {{
            text-align: center;
            color: #333;
            margin-bottom: 20px;
        }}
        label {{
            display: block;
            margin-top: 15px;
            font-weight: bold;
            color: #444;
        }}
        select, input[type="file"], button {{
            width: 100%;
            padding: 10px;
            margin-top: 5px;
            border-radius: 6px;
            border: 1px solid #ccc;
            box-sizing: border-box;
            font-size: 14px;
        }}
        button {{
            background-color: #0066cc;
            color: white;
            border: none;
            margin-top: 20px;
            cursor: pointer;
        }}
        button:hover {{
            background-color: #004d99;
        }}
        p#status {{
            margin-top: 20px;
            font-weight: bold;
            text-align: center;
        }}
        #progress {{
            margin-top: 10px;
            width: 100%;
            height: 18px;
        }}
    </style>
</head>
<body>
    <div class="container">
        <h1>🎤 Trascrizione Audio/Video</h1>
        <form id="uploadForm">
            <label for="fileInput">Seleziona un file</label>
            <input type="file" id="fileInput" accept="audio/*,video/*,.mxf" required>
            <label for="formatSelect">Formato esportazione</label>
            <select id="formatSelect">
                <option value="avid">AVID (.txt)</option>
                <option value="xml">XML</option>
                <option value="pdf">PDF</option>
            </select>
            <label for="modelSelect">Modello Whisper</label>
            <select id="modelSelect">
                <option value="tiny">tiny</option>
                <option value="base" selected>base</option>
                <option value="small">small</option>
                <option value="medium">medium</option>
                <option value="large">large</option>
            </select>
            <button type="submit">🚀 Trascrivi</button>
        </form>
        <progress id="progress" value="0" max="100"></progress>
        <p id="status"></p>
    </div>
    <script>
        document.getElementById('uploadForm').onsubmit = async (e) => {{
            e.preventDefault();
            const file = document.getElementById("fileInput").files[0];
            const format = document.getElementById("formatSelect").value;
            const model = document.getElementById("modelSelect").value;
            const formData = new FormData();
            formData.append("file", file);
            formData.append("format", format);
            formData.append("model_name", model);

            const status = document.getElementById("status");
            const progressBar = document.getElementById("progress");
            status.textContent = "⏳ In elaborazione...";
            progressBar.value = 0;

            let progress = 0;
            let interval = setInterval(() => {{
                if (progress < 95) {{
                    progress += 1;
                    progressBar.value = progress;
                }}
            }}, 300);

            const response = await fetch("/upload/", {{
                method: "POST",
                body: formData
            }});

            clearInterval(interval);
            progressBar.value = 100;

            if (response.ok) {{
                const blob = await response.blob();
                const a = document.createElement("a");
                a.href = URL.createObjectURL(blob);
                const ext = format === "avid" ? "txt" : format;
                a.download = file.name.split(".")[0] + "." + ext;
                a.click();
                status.textContent = "✅ Completato!";
            }} else {{
                status.textContent = "❌ Errore nella trascrizione.";
            }}
        }};
    </script>
</body>
</html>
"""

@app.post("/upload/")
async def upload_audio(
    file: UploadFile = File(...),
    format: str = Form(...),
    model_name: str = Form("base")
):
    os.makedirs("temp", exist_ok=True)
    base = os.path.splitext(file.filename)[0]
    path = os.path.join("temp", file.filename)
    with open(path, "wb") as f:
        f.write(await file.read())

    model = whisper.load_model(model_name, device=device)
    result = model.transcribe(path)

    subtitles = [
        srt.Subtitle(i+1, timedelta(seconds=s['start']), timedelta(seconds=s['end']), s['text'].upper())
        for i, s in enumerate(result["segments"])
    ]

    def to_tc(t, fps=25):
        sec = t.total_seconds()
        h = int(sec // 3600)
        m = int((sec % 3600) // 60)
        s = int(sec % 60)
        f = int((sec % 1) * fps)
        return f"{h:02}:{m:02}:{s:02}:{f:02}"

    ext = "txt" if format == "avid" else format
    output_path = os.path.join("temp", f"{base}.{ext}")

    if format == "avid":
        with open(output_path, "w") as out:
            out.write("@ This file written with MonniS Avid Caption plugin, version 1\n\n<begin subtitles>\n")
            for s in subtitles:
                out.write(f"{to_tc(s.start)} {to_tc(s.end)}\n{s.content}\n\n")
            out.write("<end subtitles>")

    elif format == "xml":
        with open(output_path, "w") as out:
            out.write('<?xml version="1.0" encoding="UTF-8"?>\n<subtitles>\n')
            for s in subtitles:
                out.write(f'  <subtitle start="{s.start}" end="{s.end}">{s.content}</subtitle>\n')
            out.write("</subtitles>")

    elif format == "pdf":
        pdf = FPDF()
        pdf.set_font("Arial", size=10)

        def add_header(tc_str):
            pdf.add_page()
            try:
                if os.path.exists("logosermi.png"):
                    pdf.image("logosermi.png", x=(pdf.w - 50) / 2, y=10, w=50)
                    pdf.set_y(40)
                else:
                    pdf.set_y(20)
            except Exception as e:
                logger.warning(f"Logo non inserito: {e}")
                pdf.set_y(20)
            pdf.set_x(0)
            pdf.cell(w=0, h=10, txt=f"Da: {tc_str}", align="C", ln=True)
            pdf.set_y(pdf.get_y() + 10)

        first_in_page = True
        for i, s in enumerate(subtitles):
            if first_in_page or pdf.get_y() > 270:
                tc = s.start.total_seconds()
                tc_str = f"{int(tc//3600):02}:{int((tc%3600)//60):02}:{int(tc%60):02}:{int((tc%1)*25):02}"
                add_header(tc_str)
                first_in_page = False

            line = s.content.encode("latin-1", "replace").decode("latin-1")
            pdf.multi_cell(0, 10, line)

            if pdf.get_y() > 270:
                first_in_page = True

        pdf.output(output_path, "F")

    else:
        return HTMLResponse("❌ Formato non supportato", status_code=400)

    return FileResponse(output_path, media_type="application/octet-stream", filename=os.path.basename(output_path))

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