from core.services.delete_service import delete_mod
from core import deploy_mods, initialize_and_scan_mod
from core.io import json_store
from core.logger_config import logger
from core.services import config_service
from core.services.mapcycle_service import regenerate_umc_mapcycle
from core.services.scan_service import get_available_server_cfgs
from flask import Blueprint, abort, request
from web.routes.api.utils import ApiResponse, handle_api_response

mods_api = Blueprint("mods_api", __name__)


def _is_known_cfg_path(cfg_path: str) -> bool:
    """Verifies that `cfg_path` corresponds to a .cfg file detected by the server scan."""
    if not cfg_path:
        return False
    if ".." in cfg_path or cfg_path.startswith(("/", "\\")):
        return False
    return cfg_path in get_available_server_cfgs()


@mods_api.route("/toggle/<mod_id>", methods=["POST"])
def toggle_mod(mod_id: str) -> ApiResponse:
    """Activate or deactivate a mod."""
    is_active = json_store.toggle_mod_load_order(mod_id)
    return handle_api_response({"status": "success", "active": is_active})


@mods_api.route("/save_config", methods=["POST"])
def save_mod_config() -> ApiResponse:
    """Save the configuration of mods."""
    config_service.update_configuration_workflow(request.form)

    return handle_api_response({"status": "success"})


@mods_api.route("/change_category/<mod_id>", methods=["POST"])
def change_mod_category(mod_id: str) -> ApiResponse:
    """Change the UMC target category directly in the mod's manifest.json file."""
    category = request.form.get("category", "").strip()
    if not category:
        abort(400, description="Category data is missing.")

    json_store.update_manifest_field(mod_id, "target_category", category)

    return handle_api_response({"status": "success"})


@mods_api.route("/save_commands", methods=["POST"])
def save_mod_commands() -> ApiResponse:
    """Save exec commands of mod."""
    req_data = request.json
    if not req_data or "mod_commands" not in req_data:
        abort(400, description="Missing mod_commands data.")

    config_service.save_mod_commands_workflow(req_data["mod_commands"])
    return handle_api_response(
        {"status": "success", "message": "Commands saved & UMC mapcycle updated."}
    )


@mods_api.route("/deploy", methods=["POST"])
@mods_api.route("/deploy/<mod_id>", methods=["POST"])
def run_deploy(mod_id: str | None = None) -> ApiResponse:
    """Save configuration and deploy mods."""
    config_service.update_configuration_workflow(request.form)
    force_full = request.form.get("force_full") == "true"

    if mod_id:
        stats = deploy_mods(force_full_deploy=force_full, specific_mod_id=mod_id)
    else:
        stats = deploy_mods(force_full_deploy=force_full)

    regenerate_umc_mapcycle()

    return handle_api_response(
        {
            "status": "success",
            "files_copied": stats["files_copied"],
            "files_deleted": stats["files_deleted"],
            "bytes_copied": stats["bytes_copied"],
            "readable_size": stats["readable_size"],
            "action": stats["action"],
            "scope": "single" if mod_id else "global",
        }
    )


@mods_api.route("/link_cfg/<mod_id>", methods=["POST"])
def link_cfg(mod_id: str) -> ApiResponse:
    """Manually associate a .cfg file with a mod and force a scan."""
    cfg_path = (request.form.get("path") or request.args.get("path", "")).strip()

    if not _is_known_cfg_path(cfg_path):
        logger.warning(f"[link_cfg] Rejected suspicious path for mod {mod_id}: {cfg_path!r}")
        abort(400, description="Invalid cfg path.")

    json_store.link_cfg_to_manifest(mod_id, cfg_path)
    initialize_and_scan_mod(mod_id)

    return handle_api_response({"status": "success"})


@mods_api.route("/unlink_cfg/<mod_id>", methods=["POST"])
def unlink_cfg(mod_id: str) -> ApiResponse:
    """Detaches a .cfg file from a mod and forces a scan."""
    cfg_path = (request.form.get("path") or request.args.get("path", "")).strip()

    if not _is_known_cfg_path(cfg_path):
        logger.warning(f"[unlink_cfg] Rejected suspicious path for mod {mod_id}: {cfg_path!r}")
        abort(400, description="Invalid cfg path.")

    config_service.remove_cfg_workflow(mod_id, cfg_path)
    return handle_api_response({"status": "success"})


@mods_api.route("/scan/<mod_id>", methods=["POST"])
def run_scan(mod_id: str) -> ApiResponse:
    """Force the scan of the generated file for this mod."""
    try:
        initialize_and_scan_mod(mod_id)
        return handle_api_response({"status": "success", "message": f"Mod {mod_id} scanned."})
    except Exception as e:
        logger.error(f"[Scan Error] {e}")
        return handle_api_response({"status": "error", "message": str(e)}, 500)

@mods_api.route("/delete/<mod_id>", methods=["POST"])
def delete(mod_id: str) -> ApiResponse:
    """Completely deletes a mod and all associated resources."""
    response = delete_mod(mod_id)
    return handle_api_response(response)