"""Plugin routes — list, install, activate, deactivate, uninstall, manifest schema, config."""

from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.db import get_db
from app.deps import require_permission
from app.plugins.migration_runner import MigrationValidationError
from app.services.plugin_service import get_plugin_service

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


class PluginConfigUpdate(BaseModel):
    """Request body for updating plugin configuration."""
    config: dict


@router.get("")
async def list_plugins(
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("plugins:read")),
):
    """List all plugins with their current status (discovered, installed, active, inactive)."""
    service = get_plugin_service()
    plugins = await service.list_plugins(db)
    return {"plugins": plugins, "total": len(plugins)}


@router.get("/manifest")
async def get_manifest_schema(
    current_user: dict = Depends(require_permission("plugins:read")),
):
    """Get the plugin manifest schema documentation."""
    service = get_plugin_service()
    return service.get_manifest_schema()


@router.get("/{name}/config")
async def get_plugin_config(
    name: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("plugins:read")),
):
    """Get the configuration for a specific plugin.

    Returns the plugin's config field as a JSON object.
    """
    service = get_plugin_service()
    try:
        config = await service.get_plugin_config(db, name)
        return {"name": name, "config": config}
    except ValueError as exc:
        raise HTTPException(
            404, detail={"detail": str(exc), "code": "plugin_not_found"}
        ) from None


@router.patch("/{name}/config")
async def update_plugin_config(
    name: str,
    body: PluginConfigUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("plugins:configure")),
):
    """Update the configuration for a specific plugin.

    Stores the config as a JSON string in the plugin's config field.
    """
    import uuid as uuid_mod

    service = get_plugin_service()
    try:
        result = await service.update_plugin_config(
            db,
            name,
            config=body.config,
            tenant_id=uuid_mod.UUID(current_user["tenant_id"]),
            user_id=uuid_mod.UUID(current_user["user_id"]),
        )
        return result
    except ValueError as exc:
        raise HTTPException(
            404, detail={"detail": str(exc), "code": "plugin_not_found"}
        ) from None


@router.post("/{name}/install")
async def install_plugin(
    name: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("plugins:configure")),
):
    """Install a plugin by name. Runs migrations and creates DB record.

    Idempotent: returns 200 if already installed.
    """
    import uuid as uuid_mod

    service = get_plugin_service()
    try:
        result = await service.install_plugin(
            db,
            name,
            tenant_id=uuid_mod.UUID(current_user["tenant_id"]),
            user_id=uuid_mod.UUID(current_user["user_id"]),
        )
        return result
    except ValueError as exc:
        if "not found" in str(exc).lower():
            raise HTTPException(
                404, detail={"detail": str(exc), "code": "plugin_not_found"}
            ) from None
        raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"}) from None
    except MigrationValidationError as exc:
        raise HTTPException(
            422, detail={"detail": str(exc), "code": "migration_validation_error"}
        ) from None


@router.post("/{name}/activate")
async def activate_plugin(
    name: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("plugins:configure")),
):
    """Activate a plugin by name. Registers event listeners and routes.

    Idempotent: returns 200 if already active.
    """
    import uuid as uuid_mod

    service = get_plugin_service()
    try:
        result = await service.activate_plugin(
            db,
            name,
            tenant_id=uuid_mod.UUID(current_user["tenant_id"]),
            user_id=uuid_mod.UUID(current_user["user_id"]),
        )
        return result
    except ValueError as exc:
        if "not installed" in str(exc).lower():
            raise HTTPException(
                400, detail={"detail": str(exc), "code": "plugin_not_installed"}
            ) from None
        if "not found" in str(exc).lower():
            raise HTTPException(
                404, detail={"detail": str(exc), "code": "plugin_not_found"}
            ) from None
        raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"}) from None


@router.post("/{name}/deactivate")
async def deactivate_plugin(
    name: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("plugins:configure")),
):
    """Deactivate a plugin by name. Unregisters event listeners and routes.

    Idempotent: returns 200 if already inactive.
    """
    import uuid as uuid_mod

    service = get_plugin_service()
    try:
        result = await service.deactivate_plugin(
            db,
            name,
            tenant_id=uuid_mod.UUID(current_user["tenant_id"]),
            user_id=uuid_mod.UUID(current_user["user_id"]),
        )
        return result
    except ValueError as exc:
        if "not found" in str(exc).lower():
            raise HTTPException(
                404, detail={"detail": str(exc), "code": "plugin_not_found"}
            ) from None
        raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"}) from None


@router.delete("/{name}")
async def uninstall_plugin(
    name: str,
    remove_data: bool = Query(False),
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("plugins:configure")),
):
    """Uninstall a plugin. Optionally drop plugin-created tables with remove_data=true.

    Returns 200 with uninstalled status. Idempotent for already-uninstalled plugins.
    """
    import uuid as uuid_mod

    service = get_plugin_service()
    try:
        result = await service.uninstall_plugin(
            db,
            name,
            remove_data=remove_data,
            tenant_id=uuid_mod.UUID(current_user["tenant_id"]),
            user_id=uuid_mod.UUID(current_user["user_id"]),
        )
        return result
    except ValueError as exc:
        if "not found" in str(exc).lower():
            raise HTTPException(
                404, detail={"detail": str(exc), "code": "plugin_not_found"}
            ) from None
        raise HTTPException(400, detail={"detail": str(exc), "code": "plugin_error"}) from None
