"""
Legacy API v1 Endpoints
Endpoints migrated from main.py that don't fit in other routers
Story 3.5: API Versioning
"""

import logging
import os
from pathlib import Path
from typing import Optional, Any

from fastapi import APIRouter, File, Form, UploadFile, HTTPException, Request, Depends
from fastapi.responses import FileResponse, JSONResponse

from config import config
from utils import file_handler
from utils.file_handler import validate_zip_safety
from middleware.api_key_auth import get_authenticated_user

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/v1", tags=["Legacy"])


def _resolve_model(
    cfg_model: Optional[str],
    model_env: str,
    default: str,
) -> str:
    """Resolve effective model: JSON config > env var > default."""
    v = (cfg_model or "").strip() or os.getenv(model_env, "").strip()
    return v or default


@router.get("/providers/available")
async def get_available_providers(
    current_user: Optional[Any] = Depends(get_authenticated_user),
):
    """
    Return every provider that is enabled — checking BOTH the admin settings JSON
    AND environment variables (env vars act as a fallback / override).

    Rules:
      - Google Translate is always shown.
      - Ollama is only shown in DEV mode (APP_ENV=development or SHOW_OLLAMA=true).
      - openrouter  → shown as "Traduction IA Essentielle" (cheap models).
      - openrouter_premium → shown as "Traduction IA Premium" (premium models).
      - Filtered to the engines included in the caller's plan
        (PLANS[plan]["providers"]) so the UI never offers an engine the
        translate endpoint would reject.
    """
    from routes.admin_routes import load_settings
    from models.subscription import PlanType, PLANS
    from routes.translate_routes import _resolve_tier_model

    settings = load_settings()
    is_dev = os.getenv("APP_ENV", "production").lower() == "development"
    # Le modèle affiché est celui réellement routé pour le plan de l'appelant
    # (réglages admin « ai_tiers » > défaut du plan — gamme officielle).
    user_plan = str(current_user.plan) if current_user is not None else None

    def _key_ready(key_var: str) -> bool:
        return bool(os.getenv(key_var, "").strip())

    def _url_ready(url_var: str) -> bool:
        return bool(os.getenv(url_var, "").strip())

    def _is_enabled(name: str, key_var: str = "", url_var: str = "") -> bool:
        cfg = getattr(settings, name, None)
        if cfg and cfg.enabled:
            return True
        if key_var and _key_ready(key_var):
            return True
        if url_var and _url_ready(url_var):
            return True
        return False

    available = []

    # Google Translate — always available
    available.append({
        "id": "google",
        "label": "Google Traduction",
        "description": "Traduction rapide, 130+ langues, fiable",
        "mode": "classic",
        "tier": "free",
    })

    # AI Essentielle (OpenRouter — cheap model / Eco)
    if _is_enabled("openrouter", key_var="OPENROUTER_API_KEY"):
        # La résolution renvoie la route complète (canal, modèle) — le canal
        # réel (z.ai direct, DeepSeek direct…) peut différer d'openrouter.
        _prov, model = _resolve_tier_model(settings, user_plan, premium=False)
        available.append({
            "id": "openrouter",
            "label": "Traduction IA Éco",
            "description": "IA rapide, économique et complète — supporte les images",
            "mode": "llm",
            "tier": "pro",
            "model": model,
        })

    # AI Standard (DeepSeek via OpenRouter or direct DeepSeek API)
    if _is_enabled("openrouter", key_var="OPENROUTER_API_KEY") or _is_enabled("deepseek", key_var="DEEPSEEK_API_KEY"):
        ds_cfg = getattr(settings, "deepseek", None)
        model = _resolve_model(
            ds_cfg.model if ds_cfg else None,
            "DEEPSEEK_MODEL",
            "deepseek/deepseek-chat",
        )
        available.append({
            "id": "deepseek",
            "label": "Traduction IA Standard",
            "description": "IA ultra-précise pour le texte (ne traduit pas les images)",
            "mode": "llm",
            "tier": "pro",
            "model": model,
        })

    # AI Premium (OpenRouter — premium model)
    if _is_enabled("openrouter_premium", key_var="OPENROUTER_API_KEY") or _is_enabled("openrouter", key_var="OPENROUTER_API_KEY"):
        _prov, model = _resolve_tier_model(settings, user_plan, premium=True)
        available.append({
            "id": "openrouter_premium",
            "label": "Traduction IA Premium",
            "description": "IA haut de gamme — excellente qualité littéraire et multimodal",
            "mode": "llm",
            "tier": "business",
            "model": model,
        })

    # OpenAI direct — if configured with direct API key
    if _is_enabled("openai", key_var="OPENAI_API_KEY"):
        oai_cfg = getattr(settings, "openai", None)
        model = _resolve_model(
            oai_cfg.model if oai_cfg else None,
            "OPENAI_MODEL",
            "gpt-4o-mini",
        )
        available.append({
            "id": "openai",
            "label": "OpenAI GPT",
            "description": "Traduction IA via OpenAI directement",
            "mode": "llm",
            "tier": "business",
            "model": model,
        })

    # MiniMax direct — if configured with direct API key
    if _is_enabled("minimax", key_var="MINIMAX_API_KEY"):
        mm_cfg = getattr(settings, "minimax", None)
        model = _resolve_model(
            mm_cfg.model if mm_cfg else None,
            "MINIMAX_MODEL",
            "abab6.5s-chat",
        )
        available.append({
            "id": "minimax",
            "label": "Traduction IA Avancée",
            "description": "Traduction IA haute performance",
            "mode": "llm",
            "tier": "pro",
            "model": model,
        })

    # z.AI / xAI Grok — if configured with direct API key
    if _is_enabled("zai", key_var="ZAI_API_KEY"):
        zai_cfg = getattr(settings, "zai", None)
        model = _resolve_model(
            zai_cfg.model if zai_cfg else None,
            "ZAI_MODEL",
            "grok-2-1212",
        )
        available.append({
            "id": "zai",
            "label": "Grok (xAI)",
            "description": "IA Grok par xAI — traduction avancée",
            "mode": "llm",
            "tier": "business",
            "model": model,
        })



    # Filter to the engines included in the caller's plan (anonymous → Free).
    user_plan = PlanType.FREE
    if current_user is not None:
        try:
            user_plan = PlanType(getattr(current_user, "plan", PlanType.FREE))
        except ValueError:
            user_plan = PlanType.FREE
    allowed = set((PLANS.get(user_plan) or PLANS[PlanType.FREE]).get("providers", []))
    available = [p for p in available if p.get("id") in allowed]

    return JSONResponse(
        status_code=200,
        headers={"Cache-Control": "no-cache, no-store, must-revalidate"},
        content={"providers": available}
    )


@router.get("/languages")
async def get_supported_languages():
    """Get list of supported language codes, ordered by internet popularity.

    Served from LanguageValidator (single source of truth): the 35 most
    requested languages first, then the rest of the validated ISO 639-1 set
    alphabetically. "auto" is excluded — it is a source-only value handled
    by the source_lang parameter.
    """
    from middleware.validation import LanguageValidator

    popular_order = [
        # Top 5 — dominant on the internet
        "en", "es", "de", "fr", "ja",
        # Top 6-15
        "pt", "ru", "it", "zh-CN", "zh-TW", "pl", "nl", "tr", "ko", "ar",
        # Top 16-25
        "fa", "vi", "id", "uk", "sv", "cs", "el", "he", "hi", "ro",
        # Next most requested
        "da", "fi", "no", "hu", "th", "sk", "bg", "hr", "ca", "ms", "zh",
    ]

    names = LanguageValidator.LANGUAGE_NAMES
    supported = [
        c for c in LanguageValidator.SUPPORTED_LANGUAGES if c != "auto"
    ]
    ordered = [c for c in popular_order if c in supported]
    ordered += sorted(c for c in supported if c not in ordered)

    return {
        "supported_languages": {code: names.get(code, code.upper()) for code in ordered},
        "count": len(ordered),
        "note": "Supported languages may vary depending on the translation service configured",
    }


@router.post("/translate-batch")
async def translate_batch_documents(
    files: list[UploadFile] = File(
        ..., description="Multiple document files to translate"
    ),
    target_language: str = Form(..., description="Target language code"),
    source_language: str = Form(default="auto", description="Source language code"),
    current_user: Optional[Any] = Depends(get_authenticated_user),
):
    """Translate multiple documents in batch"""
    from translators import excel_translator, word_translator, pptx_translator

    results = []

    for file in files:
        try:
            file_extension = file_handler.validate_file_extension(file.filename)
            file_handler.validate_file_size(file)

            input_filename = file_handler.generate_unique_filename(
                file.filename, "input"
            )
            output_filename = file_handler.generate_unique_filename(
                file.filename, "translated"
            )

            input_path = config.UPLOAD_DIR / input_filename
            output_path = config.OUTPUT_DIR / output_filename

            file_handler.save_upload_file(file, input_path)

            # Zip bomb protection: Office files are ZIP archives
            if file_extension != ".pdf":
                validate_zip_safety(input_path)

            if file_extension == ".xlsx":
                excel_translator.translate_file(
                    input_path, output_path, target_language, source_language
                )
            elif file_extension == ".docx":
                word_translator.translate_file(
                    input_path, output_path, target_language, source_language
                )
            elif file_extension == ".pptx":
                pptx_translator.translate_file(
                    input_path, output_path, target_language, source_language
                )

            file_handler.cleanup_file(input_path)

            results.append(
                {
                    "filename": file.filename,
                    "status": "success",
                    "output_file": output_filename,
                    "download_url": f"/api/v1/download/{output_filename}",
                }
            )

        except ValueError as e:
            file_handler.cleanup_file(input_path)
            logger.warning(f"Rejected unsafe or invalid archive: {file.filename}: {e}")
            results.append(
                {
                    "filename": file.filename,
                    "status": "error",
                    "error": "CORRUPTED_FILE",
                    "message": "Le fichier semble corrompu ou n'est pas un document Office valide.",
                    "details": {"reason": "unsafe_archive", "detail": str(e)[:200]},
                }
            )
        except Exception as e:
            logger.exception(f"Error processing {file.filename}")
            results.append(
                {
                    "filename": file.filename,
                    "status": "error",
                    "error": "INTERNAL_ERROR",
                    "message": "Erreur lors du traitement du fichier.",
                    "details": {},
                }
            )

    return {
        "total_files": len(files),
        "successful": len([r for r in results if r["status"] == "success"]),
        "failed": len([r for r in results if r["status"] == "error"]),
        "results": results,
    }


@router.post("/extract-texts")
async def extract_texts_from_document(
    file: UploadFile = File(..., description="Document file to extract texts from"),
    current_user: Optional[Any] = Depends(get_authenticated_user),
):
    """Extract all translatable texts from a document for client-side translation"""
    import uuid
    import json

    try:
        file_extension = file_handler.validate_file_extension(file.filename)
        logger.info(f"Extracting texts from {file_extension} file: {file.filename}")

        file_handler.validate_file_size(file)

        session_id = str(uuid.uuid4())

        input_filename = f"session_{session_id}{file_extension}"
        input_path = config.UPLOAD_DIR / input_filename
        file_handler.save_upload_file(file, input_path)

        if file_extension != ".pdf":
            validate_zip_safety(input_path)

        texts = []

        if file_extension == ".xlsx":
            from openpyxl import load_workbook

            wb = load_workbook(input_path)
            for sheet in wb.worksheets:
                for row in sheet.iter_rows():
                    for cell in row:
                        if (
                            cell.value
                            and isinstance(cell.value, str)
                            and cell.value.strip()
                        ):
                            texts.append(
                                {
                                    "id": f"{sheet.title}!{cell.coordinate}",
                                    "text": cell.value,
                                }
                            )
            wb.close()
        elif file_extension == ".docx":
            from docx import Document

            doc = Document(input_path)
            para_idx = 0
            for para in doc.paragraphs:
                if para.text.strip():
                    texts.append({"id": f"para_{para_idx}", "text": para.text})
                para_idx += 1
            table_idx = 0
            for table in doc.tables:
                for row_idx, row in enumerate(table.rows):
                    for cell_idx, cell in enumerate(row.cells):
                        if cell.text.strip():
                            texts.append(
                                {
                                    "id": f"table_{table_idx}_r{row_idx}_c{cell_idx}",
                                    "text": cell.text,
                                }
                            )
                table_idx += 1
        elif file_extension == ".pptx":
            from pptx import Presentation

            prs = Presentation(input_path)
            for slide_idx, slide in enumerate(prs.slides):
                for shape_idx, shape in enumerate(slide.shapes):
                    if shape.has_text_frame:
                        for para_idx, para in enumerate(shape.text_frame.paragraphs):
                            for run_idx, run in enumerate(para.runs):
                                if run.text.strip():
                                    texts.append(
                                        {
                                            "id": f"slide_{slide_idx}_shape_{shape_idx}_para_{para_idx}_run_{run_idx}",
                                            "text": run.text,
                                        }
                                    )

        session_data = {
            "original_filename": file.filename,
            "file_extension": file_extension,
            "input_path": str(input_path),
            "text_count": len(texts),
        }
        session_file = config.UPLOAD_DIR / f"session_{session_id}.json"
        with open(session_file, "w", encoding="utf-8") as f:
            json.dump(session_data, f)

        logger.info(
            f"Extracted {len(texts)} texts from {file.filename}, session: {session_id}"
        )

        return {
            "session_id": session_id,
            "texts": texts,
            "file_type": file_extension,
            "text_count": len(texts),
        }

    except HTTPException:
        raise
    except ValueError as e:
        file_handler.cleanup_file(input_path)
        logger.warning(f"Text extraction rejected unsafe or invalid archive: {file.filename}: {e}")
        return JSONResponse(
            status_code=400,
            content={
                "error": "CORRUPTED_FILE",
                "message": "Le fichier semble corrompu ou n'est pas un document Office valide.",
                "details": {"reason": "unsafe_archive", "detail": str(e)[:200]},
            },
        )
    except Exception as e:
        logger.exception("Text extraction error")
        return JSONResponse(
            status_code=500,
            content={
                "error": "INTERNAL_ERROR",
                "message": "Erreur lors de l'extraction des textes. Veuillez reessayer.",
            },
        )


@router.post("/reconstruct-document")
async def reconstruct_document(
    session_id: str = Form(..., description="Session ID from extract-texts"),
    translations: str = Form(
        ..., description="JSON array of {id, translated_text} objects"
    ),
    current_user: Optional[Any] = Depends(get_authenticated_user),
):
    """Reconstruct a document with translated texts. session_id must be a valid UUID."""
    import json
    import uuid

    try:
        uuid.UUID(session_id)
    except (ValueError, TypeError):
        raise HTTPException(status_code=400, detail="Invalid session ID")

    try:
        session_file = config.UPLOAD_DIR / f"session_{session_id}.json"
        if not session_file.exists():
            raise HTTPException(status_code=404, detail="Session not found or expired")

        with open(session_file, "r", encoding="utf-8") as f:
            session_data = json.load(f)

        input_path = Path(session_data["input_path"]).resolve()
        upload_dir_resolved = config.UPLOAD_DIR.resolve()
        if not input_path.is_relative_to(upload_dir_resolved):
            raise HTTPException(status_code=400, detail="Invalid session data")
        file_extension = session_data["file_extension"]
        original_filename = session_data["original_filename"]

        if not input_path.exists():
            raise HTTPException(
                status_code=404, detail="Source file not found or expired"
            )

        translation_list = json.loads(translations)
        translation_map = {t["id"]: t["translated_text"] for t in translation_list}

        output_filename = file_handler.generate_unique_filename(
            original_filename, "translated"
        )
        output_path = config.OUTPUT_DIR / output_filename

        if file_extension == ".xlsx":
            from openpyxl import load_workbook
            import shutil

            shutil.copy(input_path, output_path)
            wb = load_workbook(output_path)
            for sheet in wb.worksheets:
                for row in sheet.iter_rows():
                    for cell in row:
                        cell_id = f"{sheet.title}!{cell.coordinate}"
                        if cell_id in translation_map:
                            cell.value = translation_map[cell_id]
            wb.save(output_path)
            wb.close()

        elif file_extension == ".docx":
            from docx import Document
            import shutil

            shutil.copy(input_path, output_path)
            doc = Document(output_path)
            para_idx = 0
            for para in doc.paragraphs:
                para_id = f"para_{para_idx}"
                if para_id in translation_map and para.text.strip():
                    for run in para.runs:
                        run.text = ""
                    if para.runs:
                        para.runs[0].text = translation_map[para_id]
                    else:
                        para.text = translation_map[para_id]
                para_idx += 1
            table_idx = 0
            for table in doc.tables:
                for row_idx, row in enumerate(table.rows):
                    for cell_idx, cell in enumerate(row.cells):
                        cell_id = f"table_{table_idx}_r{row_idx}_c{cell_idx}"
                        if cell_id in translation_map:
                            for para in cell.paragraphs:
                                for run in para.runs:
                                    run.text = ""
                            if cell.paragraphs and cell.paragraphs[0].runs:
                                cell.paragraphs[0].runs[0].text = translation_map[
                                    cell_id
                                ]
                            elif cell.paragraphs:
                                cell.paragraphs[0].text = translation_map[cell_id]
                table_idx += 1
            doc.save(output_path)

        elif file_extension == ".pptx":
            from pptx import Presentation
            import shutil

            shutil.copy(input_path, output_path)
            prs = Presentation(output_path)
            for slide_idx, slide in enumerate(prs.slides):
                for shape_idx, shape in enumerate(slide.shapes):
                    if shape.has_text_frame:
                        for para_idx, para in enumerate(shape.text_frame.paragraphs):
                            for run_idx, run in enumerate(para.runs):
                                run_id = f"slide_{slide_idx}_shape_{shape_idx}_para_{para_idx}_run_{run_idx}"
                                if run_id in translation_map:
                                    run.text = translation_map[run_id]
            prs.save(output_path)

        file_handler.cleanup_file(input_path)
        file_handler.cleanup_file(session_file)

        logger.info(f"Reconstructed document: {output_path}")

        return FileResponse(
            path=output_path,
            filename=f"translated_{original_filename}",
            media_type="application/octet-stream",
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.exception("Reconstruction error")
        return JSONResponse(
            status_code=500,
            content={
                "error": "INTERNAL_ERROR",
                "message": "Erreur lors de la reconstruction du document. Veuillez reessayer.",
            },
        )





@router.get("/metrics")
async def get_metrics(
    current_user: Optional[Any] = Depends(get_authenticated_user),
):
    """Get system metrics and statistics for monitoring"""
    from middleware.cleanup import create_cleanup_manager
    from middleware.rate_limiting import RateLimitManager, RateLimitConfig

    cleanup_manager = create_cleanup_manager(config)
    rate_limit_config = RateLimitConfig(
        requests_per_minute=config.RATE_LIMIT_PER_MINUTE,
        requests_per_hour=config.RATE_LIMIT_PER_HOUR,
        translations_per_minute=config.TRANSLATIONS_PER_MINUTE,
        translations_per_hour=config.TRANSLATIONS_PER_HOUR,
        max_concurrent_translations=config.MAX_CONCURRENT_TRANSLATIONS,
    )
    rate_limit_manager = RateLimitManager(rate_limit_config)

    cleanup_stats = cleanup_manager.get_stats()
    rate_limit_stats = rate_limit_manager.get_stats()

    return {
        "system": {
            "memory": {},
            "disk": {},
            "status": "healthy",
        },
        "cleanup": cleanup_stats,
        "rate_limits": rate_limit_stats,
        "config": {
            "max_file_size_mb": config.MAX_FILE_SIZE_MB,
            "supported_extensions": list(config.SUPPORTED_EXTENSIONS),
            "translation_service": config.TRANSLATION_SERVICE,
        },
    }


@router.get("/rate-limit/status")
async def get_rate_limit_status(request: Request):
    """Get current rate limit status for the requesting client"""
    from middleware.rate_limiting import RateLimitManager, RateLimitConfig

    rate_limit_config = RateLimitConfig(
        requests_per_minute=config.RATE_LIMIT_PER_MINUTE,
        requests_per_hour=config.RATE_LIMIT_PER_HOUR,
        translations_per_minute=config.TRANSLATIONS_PER_MINUTE,
        translations_per_hour=config.TRANSLATIONS_PER_HOUR,
        max_concurrent_translations=config.MAX_CONCURRENT_TRANSLATIONS,
    )
    rate_limit_manager = RateLimitManager(rate_limit_config)

    client_ip = request.client.host if request.client else "unknown"
    status = await rate_limit_manager.get_client_status(client_ip)

    return {
        "client_ip": client_ip,
        "limits": {
            "requests_per_minute": rate_limit_config.requests_per_minute,
            "requests_per_hour": rate_limit_config.requests_per_hour,
            "translations_per_minute": rate_limit_config.translations_per_minute,
            "translations_per_hour": rate_limit_config.translations_per_hour,
        },
        "current_usage": status,
    }
