import logging
import os
from pathlib import Path
from typing import Any, Dict, List, Optional
from fastapi import FastAPI, HTTPException, Request, Response
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel

from auth import (
    authenticate_admin,
    change_admin_credentials,
    ensure_default_admin,
    get_admin_user,
    is_admin_initialized,
    is_ip_locked,
    revoke_session,
    setup_initial_admin,
    validate_session,
)
from config import (
    BASE_DIR,
    DEFAULT_MAX_DISK_BUFFER_MB,
    DEFAULT_SERVER_PORT,
    DEFAULT_VIDEA_CHUNK_SIZE_MB,
    DEFAULT_VIDEA_CONCURRENCY,
    DEFAULT_VK_CHUNK_SIZE_MB,
)
from database import (
    check_database_schema,
    delete_account,
    delete_video,
    get_account_by_id,
    get_accounts,
    get_all_media_items,
    get_all_videos_with_details,
    get_saved_series_list,
    get_series_episodes_from_db,
    get_setting,
    init_db,
    repair_database_schema,
    save_account,
    set_setting,
    update_account_details,
    update_account_status,
)
from episode_parser import extract_season_episode, scan_directory_for_episodes
from mozisarok_client import MozisarokClient
from providers import get_provider, list_available_providers
from queue_manager import UploadQueueManager
from settings_manager import get_centralized_settings, save_centralized_settings
from updater import apply_update, check_for_updates, get_update_server_url, set_update_server_url
from version import VERSION_INFO, __version__

from logger_config import clear_logs, get_log_file_path, get_recent_logs, setup_logging

setup_logging(level=logging.INFO)
logger = logging.getLogger("MozisarokUploader")

# Initialize database schema on startup & ensure default admin account
try:
    init_db()
    ensure_default_admin()
    logger.info("MySQL database initialized.")
except Exception as e:
    logger.error(f"Failed to initialize database on startup: {e}")

# Application & Queue Manager
app = FastAPI(title="Mozisarok Video Uploader Client", version=__version__)

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


@app.middleware("http")
async def admin_auth_middleware(request: Request, call_next):
    """
    Kiemelt biztonsági köztesréteg (Admin Auth Middleware):
    Minden védett API végpontot levéd az illetéktelen hozzáféréstől.
    """
    path = request.url.path

    # Nyilvánosan elérhető utak (statisztikus fájlok, belépési/állapot API-k)
    if (
        path == "/"
        or path.startswith("/static")
        or path.startswith("/favicon")
        or path in [
            "/api/admin/status",
            "/api/admin/setup",
            "/api/admin/login",
            "/api/version",
        ]
    ):
        return await call_next(request)

    # Ha még nem lett admin létrehozva a rendszerben, engedélyezzük az inicializálást
    if not is_admin_initialized():
        return await call_next(request)

    # Munkamenet token vizsgálata süti (HttpOnly) vagy Bearer fejléc alapján
    token = request.cookies.get("admin_session")
    if not token:
        auth_hdr = request.headers.get("Authorization", "")
        if auth_hdr.startswith("Bearer "):
            token = auth_hdr.split(" ", 1)[1].strip()

    session = validate_session(token)
    if not session:
        if path.startswith("/api/"):
            return JSONResponse(
                status_code=401,
                content={"detail": "Hitelesítés szükséges. Kérjük, jelentkezz be az admin fiókkal!"},
            )

    return await call_next(request)


queue_mgr = UploadQueueManager(videa_concurrency=DEFAULT_VIDEA_CONCURRENCY)
mozisarok = queue_mgr.mozisarok

# Static Files
static_dir = BASE_DIR / "static"
static_dir.mkdir(exist_ok=True)
app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")


# --- Pydantic Request Models ---
class AdminSetupRequest(BaseModel):
    username: str
    password: str


class AdminLoginRequest(BaseModel):
    username: str
    password: str


class AdminChangePasswordRequest(BaseModel):
    current_password: str
    new_username: Optional[str] = None
    new_password: Optional[str] = None


class AccountUpdateRequest(BaseModel):
    name: Optional[str] = None
    username: Optional[str] = None
    password: Optional[str] = None
    token: Optional[str] = None
    extra_data: Optional[Dict[str, Any]] = None
    is_active: Optional[int] = None
class MozisarokLoginRequest(BaseModel):
    username: str
    password: str


class MozisarokTokenRequest(BaseModel):
    token: str


class AccountCreateRequest(BaseModel):
    provider: str
    name: str
    username: Optional[str] = None
    password: Optional[str] = None
    token: Optional[str] = None
    cookies: Optional[str] = None
    extra_data: Optional[Dict[str, Any]] = None


class AddToQueueRequest(BaseModel):
    media_data: Dict[str, Any]
    file_path: str
    provider: str = "videa"
    account_id: Optional[int] = None
    season: Optional[int] = None
    episode: Optional[int] = None
    language: str = "Magyar"
    subtitle: Optional[str] = None
    quality: str = "1080p"
    anonymous: bool = False


class BatchAddToQueueRequest(BaseModel):
    media_data: Dict[str, Any]
    file_paths: List[str]
    provider: str = "videa"
    account_id: Optional[int] = None
    language: str = "Magyar"
    subtitle: Optional[str] = None
    quality: str = "1080p"
    anonymous: bool = False


class ScanFolderRequest(BaseModel):
    folder_path: str


class ScanFilesRequest(BaseModel):
    file_paths: List[str]


class ConcurrencyRequest(BaseModel):
    concurrency: Optional[int] = None
    videa_concurrency: Optional[int] = None
    vk_concurrency: Optional[int] = None


class ChunkSettingsRequest(BaseModel):
    videa_chunk_size_mb: Optional[int] = None
    vk_chunk_size_mb: Optional[int] = None


class ResubmitRequest(BaseModel):
    force: bool = False


class MediaResubmitRequest(BaseModel):
    media_type: str = "movie"  # 'movie' or 'tv'
    tmdb_id: int
    url: str
    season: Optional[int] = None
    episode: Optional[int] = None
    language: str = "Magyar"
    subtitle: Optional[str] = None
    quality: str = "1080p"
    anonymous: bool = False
    force: bool = False


class BatchSeriesResubmitRequest(BaseModel):
    tmdb_id: int
    season: Optional[int] = None
    only_missing: bool = True
    force: bool = False
    language: Optional[str] = "Magyar"
    quality: Optional[str] = "1080p"
    check_only: bool = False
    episodes: Optional[List[Dict[str, Any]]] = None


# --- API Routes ---

@app.get("/")
def serve_index():
    index_file = static_dir / "index.html"
    if index_file.exists():
        return FileResponse(str(index_file))
    return {"message": "Mozisarok Uploader API Running. Open /static/index.html"}


# ----------------------------------------------------
# 0. Admin Authentication & Security
# ----------------------------------------------------
@app.get("/api/admin/status")
def get_admin_status(request: Request):
    """Lekéri az admin fiók állapotát és az aktuális munkamenetet."""
    init = is_admin_initialized()
    token = request.cookies.get("admin_session")
    if not token:
        auth_hdr = request.headers.get("Authorization", "")
        if auth_hdr.startswith("Bearer "):
            token = auth_hdr.split(" ", 1)[1].strip()
    session = validate_session(token)
    return {
        "initialized": init,
        "authenticated": bool(session),
        "username": session["username"] if session else None,
    }


@app.post("/api/admin/setup")
def setup_admin_endpoint(req: AdminSetupRequest, request: Request, response: Response):
    """Kezdeti adminisztrátori fiók létrehozása."""
    if is_admin_initialized():
        raise HTTPException(status_code=400, detail="Az adminisztrátori fiók már létezik!")
    try:
        success = setup_initial_admin(req.username, req.password)
        if not success:
            raise HTTPException(status_code=400, detail="Nem sikerült létrehozni az admin fiókot.")
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))

    ip = request.headers.get("x-forwarded-for", "").split(",")[0].strip() or (request.client.host if request.client else "127.0.0.1")
    ok, token, err = authenticate_admin(req.username, req.password, ip)
    if ok and token:
        response.set_cookie(
            key="admin_session",
            value=token,
            httponly=True,
            samesite="lax",
            max_age=7200,
        )
    return {"success": True, "token": token, "username": req.username}


@app.post("/api/admin/login")
def login_admin_endpoint(req: AdminLoginRequest, request: Request, response: Response):
    """Adminisztrátori bejelentkezés brute-force védelemmel."""
    ip = request.headers.get("x-forwarded-for", "").split(",")[0].strip() or (request.client.host if request.client else "127.0.0.1")
    ok, token, err = authenticate_admin(req.username, req.password, ip)
    if not ok:
        raise HTTPException(status_code=401, detail=err or "Sikertelen bejelentkezés.")

    response.set_cookie(
        key="admin_session",
        value=token,
        httponly=True,
        samesite="lax",
        max_age=7200,
    )
    return {"success": True, "token": token, "username": req.username}


@app.post("/api/admin/logout")
def logout_admin_endpoint(request: Request, response: Response):
    """Adminisztrátori kijelentkezés és munkamenet érvénytelenítése."""
    token = request.cookies.get("admin_session")
    if not token:
        auth_hdr = request.headers.get("Authorization", "")
        if auth_hdr.startswith("Bearer "):
            token = auth_hdr.split(" ", 1)[1].strip()
    if token:
        revoke_session(token)
    response.delete_cookie("admin_session")
    return {"success": True, "message": "Sikeres kijelentkezés."}


@app.post("/api/admin/change-credentials")
def change_admin_credentials_endpoint(req: AdminChangePasswordRequest):
    """Admin felhasználónév vagy jelszó megváltoztatása."""
    try:
        ok = change_admin_credentials(
            current_password=req.current_password,
            new_username=req.new_username or "",
            new_password=req.new_password,
        )
        if not ok:
            raise HTTPException(status_code=400, detail="A jelenlegi jelszó helytelen.")
        return {"success": True, "message": "Az adminisztrátori adatok sikeresen frissítve. Kérjük, jelentkezz be újra!"}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


# ----------------------------------------------------
# 0.1 Központosított Beállítások & Verziókezelés
# ----------------------------------------------------
@app.get("/api/version")
def get_version_endpoint():
    """Visszaadja az aktuális verzió és kiadási információkat."""
    return VERSION_INFO


@app.get("/api/settings")
def get_settings_endpoint():
    """Lekéri az összes központosított beállítást."""
    return get_centralized_settings()


@app.post("/api/settings")
def save_settings_endpoint(req: Dict[str, Any]):
    """Menti a központosított beállításokat."""
    updated = save_centralized_settings(req)
    if "videa_concurrency" in req and req["videa_concurrency"]:
        try:
            queue_mgr.set_videa_concurrency(int(req["videa_concurrency"]))
        except Exception:
            pass
    if "vk_concurrency" in req and req["vk_concurrency"]:
        try:
            queue_mgr.set_vk_concurrency(int(req["vk_concurrency"]))
        except Exception:
            pass
    return {"success": True, "settings": updated}


# ----------------------------------------------------
# Database Schematic & Health Check Endpoints
# ----------------------------------------------------
@app.get("/api/database/schema")
def get_database_schema_endpoint():
    """Lekéri az adatbázis séma (schematic) részletes diagnosztikai jelentését."""
    return check_database_schema()


@app.post("/api/database/schema/repair")
def repair_database_schema_endpoint():
    """Automatikusan javítja és frissíti a hiányzó táblákat és séma oszlopokat."""
    try:
        report = repair_database_schema()
        return {"success": True, "report": report}
    except Exception as e:
        logger.exception(f"Hiba a séma javításakor: {e}")
        raise HTTPException(status_code=500, detail=str(e))


# ----------------------------------------------------
# Update Management Endpoints (PHP 8.2 Server / test.nyamnet.hu)
# ----------------------------------------------------
class UpdateApplyRequest(BaseModel):
    server_url: Optional[str] = None
    force: bool = False


@app.get("/api/updates/check")
def check_updates_endpoint(server_url: Optional[str] = None):
    """Lekérdezi az elérhető frissítéseket a megadott vagy beállított szervertől."""
    try:
        return check_for_updates(server_url)
    except Exception as e:
        logger.exception(f"Hiba a frissítések lekérésekor: {e}")
        return {
            "success": False,
            "update_available": False,
            "current_version": __version__,
            "error": str(e),
        }


@app.post("/api/updates/apply")
def apply_update_endpoint(req: Optional[UpdateApplyRequest] = None):
    """Letölti, ellenőrzi (SHA-256) és biztonságosan telepíti a frissítést."""
    server_url = req.server_url if req else None
    force = req.force if req else False
    try:
        report = apply_update(server_url=server_url, force=force)
        return report
    except Exception as e:
        logger.exception(f"Hiba a frissítés telepítésekor: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/api/updates/server-url")
def set_update_server_url_endpoint(req: Dict[str, Any]):
    """Módosítja és elmenti a használt frissítési szerver URL-jét."""
    url = str(req.get("server_url", "")).strip()
    saved = set_update_server_url(url)
    return {"success": True, "server_url": saved}



# 1. Mozisarok Auth & Validation
@app.get("/api/auth/status")
def get_auth_status():
    token = get_setting("mozisarok_token")
    is_valid = mozisarok.validate_token(token) if token else False
    return {
        "has_token": bool(token),
        "is_valid": is_valid,
        "token_preview": f"{token[:15]}..." if token and len(token) > 15 else token,
    }


@app.post("/api/auth/token")
def set_auth_token(req: MozisarokTokenRequest):
    if not req.token:
        raise HTTPException(status_code=400, detail="A token nem lehet üres.")
    is_valid = mozisarok.validate_token(req.token)
    if not is_valid:
        raise HTTPException(status_code=400, detail="A megadott Mozisarok token érvénytelen.")
    mozisarok.set_token(req.token)
    return {"success": True, "message": "Mozisarok token sikeresen elmentve."}


@app.post("/api/auth/login")
def login_mozisarok(req: MozisarokLoginRequest):
    token = mozisarok.login(req.username, req.password)
    if not token:
        raise HTTPException(status_code=401, detail="Hibás Mozisarok felhasználónév vagy jelszó.")
    return {"success": True, "token": token, "message": "Sikeres bejelentkezés."}


# 2. Mozisarok Media Search & Details
@app.get("/api/search")
def search_media(query: str):
    if not query:
        return {"results": []}
    results = mozisarok.search(query)
    return {"results": results}


@app.get("/api/media/{media_type}/{tmdb_id}")
def get_media_details(media_type: str, tmdb_id: int):
    details = mozisarok.get_media_details(media_type, tmdb_id)
    if not details:
        raise HTTPException(status_code=404, detail="Adatlap nem található a Mozisarok-on.")
    return details


@app.get("/api/media/{tmdb_id}/season/{season}")
def get_season(tmdb_id: int, season: int):
    season_data = mozisarok.get_season_details(tmdb_id, season)
    if not season_data:
        raise HTTPException(status_code=404, detail="Szezon információ nem található.")
    return season_data


# 3. Accounts Management (Videa multi-account & VK)
@app.get("/api/accounts")
def list_accounts(provider: Optional[str] = None):
    accounts = get_accounts(provider=provider)
    # Hide raw passwords in listing
    for acc in accounts:
        if acc.get("password"):
            acc["password"] = "********"
    return {"accounts": accounts, "providers": list_available_providers()}


@app.post("/api/accounts")
def create_or_update_account(req: AccountCreateRequest):
    if req.provider.lower() not in list_available_providers():
        raise HTTPException(status_code=400, detail=f"Nem támogatott szolgáltató: {req.provider}")

    acc_id = save_account(
        provider=req.provider.lower(),
        name=req.name,
        username=req.username,
        password=req.password,
        token=req.token,
        cookies=req.cookies,
        extra_data=req.extra_data,
        is_active=1,
    )
    return {"success": True, "account_id": acc_id}


@app.put("/api/accounts/{account_id}")
def edit_account(account_id: int, req: AccountUpdateRequest):
    """Fiók adatainak (név, felhasználónév, jelszó, token) módosítása."""
    acc = get_account_by_id(account_id)
    if not acc:
        raise HTTPException(status_code=404, detail="Fiók nem található.")

    success = update_account_details(
        account_id=account_id,
        name=req.name,
        username=req.username,
        password=req.password,
        token=req.token,
        extra_data=req.extra_data,
        is_active=req.is_active,
    )
    if not success:
        raise HTTPException(status_code=400, detail="Nem sikerült a fiók módosítása.")

    updated = get_account_by_id(account_id)
    if updated and updated.get("password"):
        updated["password"] = "********"
    return {"success": True, "account": updated}


@app.post("/api/accounts/{account_id}/validate")
def validate_account(account_id: int):
    acc = get_account_by_id(account_id)
    if not acc:
        raise HTTPException(status_code=404, detail="Fiók nem található.")

    provider = get_provider(acc["provider"])
    is_valid = provider.validate_credentials(acc)
    update_account_status(account_id, 1 if is_valid else 0)

    return {
        "account_id": account_id,
        "name": acc["name"],
        "provider": acc["provider"],
        "is_valid": is_valid,
    }


@app.delete("/api/accounts/{account_id}")
def remove_account(account_id: int):
    delete_account(account_id)
    return {"success": True}


# 4. Queue Management
@app.get("/api/queue")
def get_queue():
    items = queue_mgr.get_queue_status()
    return {
        "items": items,
        "is_running": queue_mgr.is_running,
        "videa_concurrency": queue_mgr.videa_concurrency,
        "vk_concurrency": queue_mgr.vk_concurrency,
        "videa_uploading_count": queue_mgr.get_videa_uploading_count(),
        "vk_uploading_count": queue_mgr.get_vk_uploading_count(),
        "videa_converting_count": queue_mgr.get_videa_converting_count(),
        "max_videa_converting": queue_mgr.max_videa_converting,
    }


@app.post("/api/queue/add")
def add_to_queue(req: AddToQueueRequest):
    try:
        task_id = queue_mgr.add_task(
            media_data=req.media_data,
            file_path=req.file_path,
            provider=req.provider,
            account_id=req.account_id,
            season=req.season,
            episode=req.episode,
            language=req.language,
            subtitle=req.subtitle,
            quality=req.quality,
            anonymous=req.anonymous,
        )
        return {"success": True, "task_id": task_id}
    except Exception as e:
        logger.error(f"Error adding to queue: {e}")
        raise HTTPException(status_code=400, detail=str(e))


@app.post("/api/queue/add-batch")
def add_batch_to_queue(req: BatchAddToQueueRequest):
    try:
        task_ids = queue_mgr.add_batch_tasks(
            media_data=req.media_data,
            file_paths=req.file_paths,
            provider=req.provider,
            account_id=req.account_id,
            language=req.language,
            subtitle=req.subtitle,
            quality=req.quality,
            anonymous=req.anonymous,
        )
        return {"success": True, "count": len(task_ids), "task_ids": task_ids}
    except Exception as e:
        logger.error(f"Error adding batch to queue: {e}")
        raise HTTPException(status_code=400, detail=str(e))


@app.get("/api/series/parse-episode")
def parse_episode_filename(filename: str):
    season, episode = extract_season_episode(filename)
    return {
        "filename": filename,
        "season": season,
        "episode": episode,
        "found": season is not None or episode is not None,
    }


@app.post("/api/series/scan-folder")
def scan_folder_episodes(req: ScanFolderRequest):
    episodes = scan_directory_for_episodes(req.folder_path)
    return {"folder_path": req.folder_path, "episodes": episodes, "count": len(episodes)}


@app.post("/api/series/scan-files")
def scan_files_episodes(req: ScanFilesRequest):
    episodes = []
    video_exts = {".mp4", ".mkv", ".avi", ".mov", ".wmv", ".flv", ".webm", ".m4v", ".ts"}
    for fp in req.file_paths:
        p = Path(fp)
        if p.is_file() and p.suffix.lower() in video_exts:
            s, e = extract_season_episode(str(p))
            episodes.append({
                "file_path": str(p.resolve()),
                "file_name": p.name,
                "file_size": p.stat().st_size,
                "season": s,
                "episode": e,
            })
    episodes.sort(key=lambda x: (x["season"] if x["season"] is not None else 999, x["episode"] if x["episode"] is not None else 999, x["file_name"]))
    return {"episodes": episodes, "count": len(episodes)}


@app.delete("/api/queue/{task_id}")
def delete_from_queue(task_id: int):
    try:
        success = queue_mgr.remove_task(task_id)
        return {"success": success}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))


@app.post("/api/queue/{task_id}/cancel")
def cancel_queue_task(task_id: int):
    try:
        success = queue_mgr.cancel_task(task_id)
        return {"success": success}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))


@app.post("/api/queue/clear-completed")
def clear_completed_tasks():
    queue_mgr.clear_completed()
    return {"success": True}


@app.post("/api/queue/start")
def start_queue():
    queue_mgr.start_queue()
    return {"success": True, "is_running": queue_mgr.is_running}


@app.post("/api/queue/stop")
def stop_queue():
    queue_mgr.stop_queue()
    return {"success": True, "is_running": queue_mgr.is_running}


@app.post("/api/queue/recover")
def recover_queue():
    """Recovers interrupted tasks and verifies uncompleted items from the MySQL database."""
    summary = queue_mgr.recover_from_database(run_in_background=False)
    return {"success": True, "recovery_summary": summary}


@app.post("/api/videos/{video_id}/force-check")
def force_check_video_endpoint(video_id: int):
    """Manually forces check, scraper conversion, and Mozisarok verification for a video."""
    res = queue_mgr.force_check_video(video_id)
    return res


@app.post("/api/queue/{task_id}/force-check")
def force_check_queue_task_endpoint(task_id: int):
    """Manually forces check, scraper conversion, and Mozisarok verification for a queue task."""
    res = queue_mgr.force_check_video(task_id)
    return res


@app.post("/api/videos/{video_id}/resubmit")
def resubmit_video_endpoint(video_id: int, req: Optional[ResubmitRequest] = None):
    """
    Checks if video's embed link is already on Mozisarok for this title/episode,
    and resubmits if missing (or forced).
    """
    force = req.force if req else False
    res = queue_mgr.resubmit_video_to_mozisarok(video_id, force=force)
    return res


@app.post("/api/media/check-and-submit")
def check_and_submit_media_endpoint(req: MediaResubmitRequest):
    """
    Checks if the given embed URL is already present on Mozisarok for a movie or TV episode,
    and submits it if not already present (or forced).
    """
    res = mozisarok.check_and_resubmit_link(
        media_type=req.media_type,
        tmdb_id=req.tmdb_id,
        url=req.url,
        language=req.language,
        subtitle=req.subtitle,
        quality=req.quality,
        season=req.season,
        episode=req.episode,
        anonymous=req.anonymous,
        force=req.force,
    )
    return res


@app.get("/api/media/{media_type}/{tmdb_id}/links")
def get_media_links_endpoint(media_type: str, tmdb_id: int, season: Optional[int] = None, episode: Optional[int] = None):
    """Fetches active links for content from Mozisarok."""
    links = mozisarok.get_links(media_type, tmdb_id, season=season, episode=episode)
    return {"links": links, "count": len(links)}


@app.get("/api/series/saved")
def get_saved_series_endpoint():
    """Lists saved TV series from MySQL with episode counts and seasons."""
    series = get_saved_series_list()
    return {"series": series, "count": len(series)}


@app.get("/api/series/{tmdb_id}/episodes")
def get_series_episodes_endpoint(tmdb_id: int, season: Optional[int] = None):
    """Lists all saved episodes for a TV series from MySQL."""
    episodes = get_series_episodes_from_db(tmdb_id, season=season)
    return {"tmdb_id": tmdb_id, "season": season, "episodes": episodes, "count": len(episodes)}


@app.post("/api/series/batch-resubmit")
def batch_resubmit_series_endpoint(req: BatchSeriesResubmitRequest):
    """
    Batch checks and submits all (or only missing) episodes of a TV series to Mozisarok.
    """
    res = queue_mgr.check_and_submit_series_batch(
        tmdb_id=req.tmdb_id,
        season=req.season,
        only_missing=req.only_missing,
        force=req.force,
        language=req.language,
        quality=req.quality,
        check_only=req.check_only,
        episodes_data=req.episodes,
    )
    return res


@app.post("/api/queue/concurrency")
def set_concurrency(req: ConcurrencyRequest):
    if req.videa_concurrency is not None:
        queue_mgr.set_videa_concurrency(req.videa_concurrency)
    elif req.concurrency is not None:
        queue_mgr.set_videa_concurrency(req.concurrency)
    if req.vk_concurrency is not None:
        queue_mgr.set_vk_concurrency(req.vk_concurrency)
    return {
        "success": True,
        "videa_concurrency": queue_mgr.videa_concurrency,
        "vk_concurrency": queue_mgr.vk_concurrency,
    }


# Chunk Size Settings (Videa & VK külön beállítható, alapértelmezett: 16 MB)
@app.get("/api/settings/chunks")
def get_chunk_settings():
    videa_mb = get_setting("videa_chunk_size_mb")
    vk_mb = get_setting("vk_chunk_size_mb")
    return {
        "videa_chunk_size_mb": int(videa_mb) if videa_mb and videa_mb.isdigit() else DEFAULT_VIDEA_CHUNK_SIZE_MB,
        "vk_chunk_size_mb": int(vk_mb) if vk_mb and vk_mb.isdigit() else DEFAULT_VK_CHUNK_SIZE_MB,
    }


@app.post("/api/settings/chunks")
def update_chunk_settings(req: ChunkSettingsRequest):
    if req.videa_chunk_size_mb is not None:
        set_setting("videa_chunk_size_mb", str(max(1, req.videa_chunk_size_mb)))
    if req.vk_chunk_size_mb is not None:
        set_setting("vk_chunk_size_mb", str(max(1, req.vk_chunk_size_mb)))
    return {"success": True, "settings": get_chunk_settings()}


# 5. Database History & Saved Videos
@app.get("/api/history")
def get_upload_history():
    videos = get_all_videos_with_details()
    media_items = get_all_media_items()
    return {"videos": videos, "media_items": media_items}


@app.delete("/api/history/{video_id}")
def remove_history_video(video_id: int):
    delete_video(video_id)
    return {"success": True}


# 6. Cross-platform Local Filesystem Browser Helper
@app.get("/api/filesystem/browse")
def browse_filesystem(current_path: Optional[str] = None):
    """
    Keresztplatformos helyi fájl- és mappaböngésző.
    Automatikusan megjegyzi a legutóbb megnyitott mappát, és támogatja az egyedi alapértelmezett kezdőmappát.
    """
    remember_folder = get_setting("remember_last_folder", "true").lower() in ("true", "1", "yes")
    default_folder = get_setting("default_browse_folder", "")
    last_folder = get_setting("last_browse_folder", "")

    if not current_path or not current_path.strip():
        # 1. Ha a legutóbbi mappa megjegyzése aktív és létezik
        if remember_folder and last_folder and Path(last_folder).is_dir():
            target = Path(last_folder)
        # 2. Ha van beállított kezdőmappa és létezik
        elif default_folder and Path(default_folder).is_dir():
            target = Path(default_folder)
        else:
            target = BASE_DIR
    else:
        target = Path(current_path)

    if not target.exists() or not target.is_dir():
        target = BASE_DIR

    # Legutóbb megnyitott mappa megjegyzése
    try:
        set_setting("last_browse_folder", str(target.resolve()))
    except Exception:
        pass

    entries = []
    parent = str(target.parent) if target.parent != target else None

    try:
        if target.is_dir():
            for item in sorted(target.iterdir(), key=lambda p: (not p.is_dir(), p.name.lower())):
                # Filter hidden files or node_modules / .git
                if item.name.startswith(".") or item.name in ["__pycache__", "venv"]:
                    continue
                entries.append({
                    "name": item.name,
                    "path": str(item.resolve()),
                    "is_dir": item.is_dir(),
                    "size": item.stat().st_size if item.is_file() else 0,
                    "is_video": item.suffix.lower() in [".mp4", ".mkv", ".avi", ".mov", ".webm", ".ts", ".m4v"],
                })
    except PermissionError:
        raise HTTPException(status_code=403, detail="Nincs jogosultság a mappa olvasásához.")

    return {
        "current_path": str(target.resolve()),
        "parent_path": parent,
        "entries": entries,
    }


# ----------------------------------------------------
# 7. Rendszernapló (System Logs & Debugging)
# ----------------------------------------------------
@app.get("/api/logs")
def get_logs_endpoint(
    limit: int = 150,
    level: Optional[str] = None,
    source: Optional[str] = None,
    search: Optional[str] = None,
):
    """Fetches recent system logs with optional level, source, and search filters."""
    safe_limit = max(10, min(limit, 2000))
    return get_recent_logs(limit=safe_limit, level=level, source=source, search=search)


@app.get("/api/logs/download")
def download_logs_endpoint():
    """Downloads the persistent app.log file."""
    log_path = get_log_file_path()
    if not log_path.exists():
        raise HTTPException(status_code=404, detail="A naplófájl még nem jött létre.")
    from datetime import datetime
    timestamp_str = datetime.now().strftime("%Y%m%d_%H%M%S")
    return FileResponse(
        path=str(log_path),
        filename=f"uploader_log_{timestamp_str}.log",
        media_type="text/plain; charset=utf-8",
    )


@app.delete("/api/logs")
def clear_logs_endpoint():
    """Clears the in-memory log buffer."""
    clear_logs()
    return {"success": True, "message": "Rendszernapló sikeresen kiürítve."}

