"""
Raw Download Routes - Sharing Link Mode
Handles Synology sharing link downloads (với Selenium + OTP).
"""

from fastapi import APIRouter, HTTPException, Request, Response
from pydantic import BaseModel
from typing import List, Dict, Optional
import logging
import os
import uuid
import time
from collections import defaultdict

from ..services import mongodb_service, nas_service, nas_sharing_service, supabase_service, downloads_service
from ..common import get_download_destination_path

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/sharing-link", tags=["Raw Sharing"])

# ==================== RATE LIMITING ====================
# Track last request time per sharing_id to prevent NAS API rate limit errors
_last_request_time: Dict[str, float] = defaultdict(float)
_rate_limit_window_ms = 200  # Minimum 200ms between requests for same sharing_id


# ==================== REQUEST MODELS ====================

class SharingLinkRequest(BaseModel):
    url: str


class SharingLinkDownloadRequest(BaseModel):
    sharing_id: str
    files: List[Dict]  # List of file objects with name, path, isdir
    ge_id: Optional[str] = None  # Optional: for organizing files by project
    lang: Optional[str] = None  # Optional: for organizing files by project


class SharingLinkFromDbRequest(BaseModel):
    ge_id: str
    lang: str


class SharingOtpSubmit(BaseModel):
    otp_code: str


# ==================== SHARING LINK PROCESSING ====================

@router.post('/get-from-db')
def get_sharing_link_from_db(payload: SharingLinkFromDbRequest):
    """
    Query MongoDB titles_data collection to get linkRaw field.
    Returns sharing link from database or throws error with record details.
    """
    try:
        # Query MongoDB
        collection = mongodb_service.get_titles_collection()
        query = {
            "geId": str(payload.ge_id).strip(),
            "lang": str(payload.lang).strip().upper()
        }

        # Find all matching records
        documents = list(collection.find(query))

        # Validation 1: No records found
        if len(documents) == 0:
            raise HTTPException(
                status_code=404,
                detail={
                    "error": "Không tìm thấy record",
                    "query": {"geId": payload.ge_id, "lang": payload.lang.upper()}
                }
            )

        # Validation 2: Multiple records (should not happen with unique constraint)
        if len(documents) > 1:
            record_info = [
                {
                    "geId": doc.get("geId"),
                    "lang": doc.get("lang"),
                    "linkRaw": doc.get("linkRaw"),
                    "path": doc.get("path")
                }
                for doc in documents
            ]
            raise HTTPException(
                status_code=400,
                detail={
                    "error": "Tìm thấy nhiều hơn 1 record",
                    "records": record_info
                }
            )

        # Get single record
        document = documents[0]
        link_raw = document.get("linkRaw")

        # Validation 3: linkRaw is empty or null
        if not link_raw or not isinstance(link_raw, str) or link_raw.strip() == "":
            record_info = {
                "geId": document.get("geId"),
                "lang": document.get("lang"),
                "linkRaw": link_raw,
                "path": document.get("path")
            }
            raise HTTPException(
                status_code=400,
                detail={
                    "error": "Trường linkRaw trống hoặc null",
                    "record": record_info
                }
            )

        # Validation 4: linkRaw is not a valid link
        link_raw_stripped = link_raw.strip()
        if not (link_raw_stripped.startswith("http://") or link_raw_stripped.startswith("https://")):
            record_info = {
                "geId": document.get("geId"),
                "lang": document.get("lang"),
                "linkRaw": link_raw,
                "path": document.get("path")
            }
            raise HTTPException(
                status_code=400,
                detail={
                    "error": "linkRaw không phải là liên kết hợp lệ (phải bắt đầu bằng http:// hoặc https://)",
                    "record": record_info
                }
            )

        # Success - return sharing link
        return {
            "success": True,
            "sharing_link": link_raw_stripped,
            "record": {
                "geId": document.get("geId"),
                "lang": document.get("lang"),
                "path": document.get("path")
            }
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error querying MongoDB for sharing link: {e}")
        raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {e}")


@router.post('/process')
def process_sharing_link(payload: SharingLinkRequest):
    """
    Process sharing link to extract file list.
    Returns: request_id for polling result
    """
    try:
        # Validate URL format
        if not payload.url or 'sharing' not in payload.url:
            raise HTTPException(status_code=400, detail="URL không hợp lệ")

        # Submit to worker queue
        result = nas_sharing_service.process_sharing_link(payload.url)

        return {
            "success": True,
            "request_id": result['request_id'],
            "status": result['status'],
            "message": "Đang xử lý sharing link..."
        }

    except Exception as e:
        logger.error(f"Error processing sharing link: {e}")
        raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {e}")


@router.get('/related-projects')
def get_related_projects(link_raw: str):
    """
    Tìm tất cả GE projects có cùng sharing link (linkRaw).

    Query params:
        link_raw: Sharing link URL

    Returns:
        {
            "success": true,
            "projects": [
                {"ge_id": "1000", "lang": "DE"},
                {"ge_id": "2000", "lang": "KO"}
            ],
            "total": 2
        }
    """
    try:
        if not link_raw or not link_raw.strip():
            raise HTTPException(
                status_code=400, detail="link_raw không được rỗng")

        link_raw_normalized = link_raw.strip()

        # Query MongoDB titles_data - tìm tất cả records có cùng linkRaw
        collection = mongodb_service.get_titles_collection()
        documents = list(collection.find(
            {"linkRaw": link_raw_normalized},
            {"geId": 1, "lang": 1, "_id": 0}  # Chỉ lấy geId và lang
        ))

        # Format kết quả
        projects = [
            {
                "ge_id": doc.get("geId"),
                "lang": doc.get("lang")
            }
            for doc in documents
        ]

        logger.debug(
            f"Found {len(projects)} projects with linkRaw: {link_raw_normalized}")

        return {
            "success": True,
            "projects": projects,
            "total": len(projects)
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error querying related projects: {e}")
        raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {e}")


@router.get('/related-projects-by-ge')
def get_related_projects_by_ge(ge_id: str, lang: str):
    """
    Tìm tất cả GE projects có cùng sharing link dựa trên ge_id và lang.

    Query params:
        ge_id: GE ID
        lang: Language code

    Returns:
        {
            "success": true,
            "projects": [
                {"ge_id": "1000", "lang": "DE"},
                {"ge_id": "2000", "lang": "KO"}
            ],
            "total": 2
        }
    """
    try:
        if not ge_id or not ge_id.strip():
            raise HTTPException(
                status_code=400, detail="ge_id không được rỗng")
        if not lang or not lang.strip():
            raise HTTPException(status_code=400, detail="lang không được rỗng")

        # Step 1: Get linkRaw from titles_data
        link_raw = mongodb_service.get_sharing_link_from_tms_data(ge_id, lang)
        if not link_raw:
            return {
                "success": True,
                "projects": [],
                "total": 0
            }

        # Step 2: Find all projects with same linkRaw
        collection = mongodb_service.get_titles_collection()
        documents = list(collection.find(
            {"linkRaw": link_raw},
            {"geId": 1, "lang": 1, "_id": 0}
        ))

        # Format kết quả
        projects = [
            {
                "ge_id": doc.get("geId"),
                "lang": doc.get("lang")
            }
            for doc in documents
        ]

        logger.debug(
            f"Found {len(projects)} related projects for GE {ge_id} {lang}")

        return {
            "success": True,
            "projects": projects,
            "total": len(projects)
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error querying related projects by GE: {e}")
        raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {e}")


@router.get('/project-note')
def get_project_note(ge_id: str, lang: str):
    """
    Lấy note từ collection titlelist_data cho GE project cụ thể.

    Query params:
        ge_id: GE ID
        lang: Language code

    Returns:
        {
            "success": true,
            "note": "Content of note field"
        }
    """
    try:
        if not ge_id or not ge_id.strip():
            raise HTTPException(
                status_code=400, detail="ge_id không được rỗng")
        if not lang or not lang.strip():
            raise HTTPException(status_code=400, detail="lang không được rỗng")

        # Query MongoDB titlelist_data collection
        db = mongodb_service.get_db_connection()
        collection = db['titlelist_data']

        document = collection.find_one(
            {
                "geId": str(ge_id).strip(),
                "lang": str(lang).strip().upper()
            },
            {"note": 1, "_id": 0}
        )

        if not document:
            return {
                "success": True,
                "note": None
            }

        note_content = document.get("note")

        logger.debug(f"Found note for {ge_id} {lang}: {bool(note_content)}")

        return {
            "success": True,
            "note": note_content if note_content else None
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error querying project note: {e}")
        raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {e}")


@router.get('/result/{request_id}')
def get_sharing_result(request_id: str):
    """
    Poll result of sharing link processing.

    Returns:
    - status: "pending" | "success" | "error"
    - If success: sharing_id, path, files, total_files
    - If error: message
    """
    try:
        result = nas_sharing_service.get_sharing_result(request_id)

        if not result:
            raise HTTPException(
                status_code=404, detail="Request không tồn tại")

        return result

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error getting sharing result: {e}")
        raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {e}")


# ==================== FOLDER NAVIGATION ====================

@router.post('/list-folder')
def list_sharing_folder(payload: dict):
    """
    List contents of a subfolder in sharing link.
    Used when user double-clicks a folder in sharing link file list.

    Payload:
    - sharing_id: Sharing ID from initial process
    - folder_path: Path to folder to list (e.g., "/subfolder_name")

    Returns:
    - status: "success" | "error"
    - files: List of files/folders
    - path: Current folder path
    """
    try:
        sharing_id = payload.get('sharing_id')
        folder_path = payload.get('folder_path', '/')

        if not sharing_id:
            raise HTTPException(
                status_code=400, detail="sharing_id là bắt buộc")

        # CRITICAL FIX: Rate limiting to prevent Error 407 from rapid requests
        current_time = time.time() * 1000  # Convert to milliseconds
        last_time = _last_request_time[sharing_id]
        time_since_last = current_time - last_time

        if time_since_last < _rate_limit_window_ms:
            wait_time = (_rate_limit_window_ms - time_since_last) / 1000
            logger.warning(
                f"Rate limit hit for {sharing_id}, rejecting request (wait {wait_time:.2f}s)")
            raise HTTPException(
                status_code=429,
                detail=f"Vui lòng chậm lại, đợi {wait_time:.1f}s trước khi thao tác tiếp"
            )

        # Update last request time
        _last_request_time[sharing_id] = current_time

        # Get sharing worker instance
        worker = nas_sharing_service.get_sharing_worker()

        if not worker or not worker.driver:
            raise HTTPException(
                status_code=503, detail="Sharing worker không sẵn sàng")

        # CRITICAL FIX: Lock driver to prevent race conditions
        # Without lock, multiple users can navigate simultaneously and conflict
        with worker.driver_lock:
            # List folder using nas_sharing_api package
            from ..services.nas_sharing_api import get_file_list
            logger.debug(
                f"📂 [Navigation] Lấy danh sách subfolder: {folder_path}")
            files = get_file_list(
                driver=worker.driver,
                sharing_id=sharing_id,
                folder_path=folder_path
            )

        logger.debug(
            f"✅ [Navigation] Tìm thấy {len(files)} items trong: {folder_path}")

        return {
            "status": "success",
            "files": files,
            "path": folder_path,
            "message": f"Tìm thấy {len(files)} item(s)"
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error listing sharing folder: {e}")
        import traceback
        traceback.print_exc()
        raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {e}")


# ==================== DOWNLOAD ENDPOINTS ====================

@router.post('/download')
def download_sharing_files(payload: SharingLinkDownloadRequest):
    """
    Download files from sharing link to NAS raw folder.
    If ge_id and lang provided, files go to \\NAS_PATH\\{ge_id}_{lang}\\ (same as API download).
    Otherwise, files go directly to \\NAS_PATH\\ root.
    """
    try:
        logger.debug(
            f"Creating sharing link download job: {payload.sharing_id}, {len(payload.files)} files")

        if not payload.files:
            return {
                "status": "error",
                "message": "Không có file nào được chọn để tải xuống"
            }

        # Calculate destination path
        if payload.ge_id and payload.lang:
            # Use same logic as API download: \\172.16.14.240\\raw\\11_US\\
            destination_path = get_download_destination_path(
                payload.ge_id, payload.lang)
            ge_id_for_db = payload.ge_id
            lang_for_db = payload.lang
        else:
            # Fallback: direct to root (backward compatible with old logic)
            destination_path = nas_service.DESTINATION_PATH
            ge_id_for_db = f"SHARING_{payload.sharing_id}"
            lang_for_db = "LINK"

        # ✅ FIX: Use downloads_service (NEW) instead of supabase_service (OLD)
        result = downloads_service.create_downloads_batch(
            files=payload.files,
            ge_id=ge_id_for_db,
            lang=lang_for_db,
            mode='sharing',  # Sharing link mode
            sharing_id=payload.sharing_id,
            mongodb_path=None,  # No MongoDB path for sharing links
            destination_path=destination_path
        )

        if not result['success']:
            return {
                "status": "error",
                "message": result.get('message', 'Không thể tạo batch downloads')
            }

        logger.debug(
            f"Created sharing batch: {result['batch_id']} ({result['file_count']} files)")

        return {
            "status": "pending",
            "message": "Batch đã được tạo và đang chờ xử lý",
            "batch_id": result['batch_id'],
            "download_ids": result['download_ids'],
            "file_count": result['file_count'],
            "destination_path": destination_path,
            "sharing_id": payload.sharing_id
        }

    except Exception as e:
        logger.error(f"Error creating sharing download job: {e}")
        raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {e}")


# ==================== OTP HANDLING ====================


@router.get('/download-status/{batch_id}')
def get_sharing_download_status(batch_id: str):
    """
    Get the status of a sharing link download batch.
    Returns batch summary with all files' status.
    """
    try:
        summary = downloads_service.get_batch_summary(batch_id)

        if not summary:
            raise HTTPException(status_code=404, detail="Batch không tồn tại")

        return {
            "success": True,
            "batch": summary
        }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error getting sharing download job status: {e}")
        raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {e}")


# ==================== OTP HANDLING ====================

@router.get('/otp-status')
def check_sharing_otp_status():
    """
    Check if sharing worker is waiting for OTP

    Returns:
        - otp_required: bool
    """
    try:
        otp_required = nas_sharing_service.is_otp_required()
        return {
            "otp_required": otp_required,
            "message": "Vui lòng nhập mã OTP" if otp_required else "Không cần OTP"
        }
    except Exception as e:
        logger.error(f"Error checking OTP status: {e}")
        raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {e}")


@router.post('/submit-otp')
def submit_sharing_otp(payload: SharingOtpSubmit):
    """
    Submit OTP code for sharing link login

    Args:
        otp_code: OTP code from user

    Returns:
        - status: "success" | "error"
        - message: Status message
    """
    try:
        status, message = nas_sharing_service.submit_otp(payload.otp_code)

        if status == "success":
            return {
                "success": True,
                "message": message
            }
        else:
            raise HTTPException(status_code=400, detail=message)

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error submitting OTP: {e}")
        raise HTTPException(status_code=500, detail=f"Lỗi hệ thống: {e}")
