"""Atlassian Rovo MCP Channel API routes.

Provides per-agent Atlassian integration configuration.
Unlike Slack/Discord (messaging channels), Atlassian is a tool-access channel:
the agent uses Jira, Confluence, and Compass via the Atlassian Rovo MCP server.
"""

import uuid

from fastapi import APIRouter, Depends, HTTPException
from loguru import logger
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.permissions import check_agent_access, is_agent_creator
from app.core.security import get_current_user
from app.database import get_db
from app.models.channel_config import ChannelConfig
from app.models.user import User

router = APIRouter(tags=["atlassian"])

ATLASSIAN_MCP_URL = "https://mcp.atlassian.com/v1/mcp"


# ─── Config CRUD ────────────────────────────────────────

@router.post("/agents/{agent_id}/atlassian-channel", status_code=201)
async def configure_atlassian_channel(
    agent_id: uuid.UUID,
    data: dict,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Configure Atlassian Rovo MCP for an agent.

    Required field: api_key (Bearer token starting with ATSTT, or Basic base64(email:token)).
    Optional: cloud_id (Atlassian cloud site ID for multi-site setups).
    """
    agent, _ = await check_agent_access(db, current_user, agent_id)
    if not is_agent_creator(current_user, agent):
        raise HTTPException(status_code=403, detail="Only creator can configure channel")

    api_key = (data.get("api_key") or "").strip()
    if not api_key:
        raise HTTPException(status_code=422, detail="api_key is required")

    cloud_id = (data.get("cloud_id") or "").strip()

    from app.core.security import encrypt_data
    from app.config import get_settings
    encrypted_key = encrypt_data(api_key, get_settings().SECRET_KEY)

    result = await db.execute(
        select(ChannelConfig).where(
            ChannelConfig.agent_id == agent_id,
            ChannelConfig.channel_type == "atlassian",
        )
    )
    existing = result.scalar_one_or_none()
    if existing:
        existing.app_secret = encrypted_key
        existing.is_configured = True
        existing.extra_config = {**(existing.extra_config or {}), "cloud_id": cloud_id}
        await db.commit()
        # Sync tools for this agent in background
        import asyncio
        asyncio.create_task(_sync_atlassian_tools_for_agent(agent_id, api_key))
        return _serialize(existing)

    config = ChannelConfig(
        agent_id=agent_id,
        channel_type="atlassian",
        app_id="atlassian",
        app_secret=encrypted_key,
        is_configured=True,
        extra_config={"cloud_id": cloud_id},
    )
    db.add(config)
    await db.commit()
    await db.refresh(config)
    # Sync tools for this agent in background
    import asyncio
    asyncio.create_task(_sync_atlassian_tools_for_agent(agent_id, api_key))
    return _serialize(config)


@router.get("/agents/{agent_id}/atlassian-channel")
async def get_atlassian_channel(
    agent_id: uuid.UUID,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    await check_agent_access(db, current_user, agent_id)
    result = await db.execute(
        select(ChannelConfig).where(
            ChannelConfig.agent_id == agent_id,
            ChannelConfig.channel_type == "atlassian",
        )
    )
    config = result.scalar_one_or_none()
    if not config:
        raise HTTPException(status_code=404, detail="Atlassian not configured")
    return _serialize(config)


@router.delete("/agents/{agent_id}/atlassian-channel", status_code=204)
async def delete_atlassian_channel(
    agent_id: uuid.UUID,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    agent, _ = await check_agent_access(db, current_user, agent_id)
    if not is_agent_creator(current_user, agent):
        raise HTTPException(status_code=403, detail="Only creator can remove channel")
    result = await db.execute(
        select(ChannelConfig).where(
            ChannelConfig.agent_id == agent_id,
            ChannelConfig.channel_type == "atlassian",
        )
    )
    config = result.scalar_one_or_none()
    if not config:
        raise HTTPException(status_code=404, detail="Atlassian not configured")
    await db.delete(config)
    await db.commit()


@router.post("/agents/{agent_id}/atlassian-channel/test")
async def test_atlassian_channel(
    agent_id: uuid.UUID,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Test connectivity to Atlassian Rovo MCP and list available tools."""
    await check_agent_access(db, current_user, agent_id)
    result = await db.execute(
        select(ChannelConfig).where(
            ChannelConfig.agent_id == agent_id,
            ChannelConfig.channel_type == "atlassian",
        )
    )
    config = result.scalar_one_or_none()
    if not config or not config.app_secret:
        raise HTTPException(status_code=400, detail="Atlassian not configured")

    from app.services.mcp_client import MCPClient
    try:
        client = MCPClient(ATLASSIAN_MCP_URL, api_key=config.app_secret)
        tools = await client.list_tools()
        return {
            "ok": True,
            "tool_count": len(tools),
            "tools": [{"name": t["name"], "description": t.get("description", "")[:100]} for t in tools[:10]],
            "message": f"✅ Connected to Atlassian Rovo MCP — {len(tools)} tools available",
        }
    except Exception as e:
        return {"ok": False, "error": str(e)[:300]}


# ─── Internal helper ────────────────────────────────────

def _serialize(config: ChannelConfig) -> dict:
    return {
        "id": str(config.id),
        "agent_id": str(config.agent_id),
        "channel_type": config.channel_type,
        "is_configured": config.is_configured,
        "is_connected": config.is_connected,
        "cloud_id": (config.extra_config or {}).get("cloud_id", ""),
        "extra_config": config.extra_config or {},
        "created_at": config.created_at.isoformat() if config.created_at else None,
    }


# ─── Utility for internal use ──────────────────────────

async def _sync_atlassian_tools_for_agent(agent_id: uuid.UUID, api_key: str) -> None:
    """Connect to Atlassian Rovo MCP and ensure all tools are seeded + assigned to this agent.

    Discovers tools from the MCP server, creates Tool records if needed,
    and creates AgentTool assignments for this specific agent.
    """
    from app.services.mcp_client import MCPClient
    from app.models.tool import Tool, AgentTool
    from app.database import async_session
    from sqlalchemy import select as sa_select

    logger.info(f"[AtlassianChannel] Syncing tools for agent {agent_id} ...")
    try:
        client = MCPClient(ATLASSIAN_MCP_URL, api_key=api_key)
        tools_discovered = await client.list_tools()
    except Exception as e:
        logger.error(f"[AtlassianChannel] Could not list tools: {e}")
        return

    if not tools_discovered:
        logger.warning("[AtlassianChannel] No tools returned from Atlassian MCP")
        return

    logger.info(f"[AtlassianChannel] Found {len(tools_discovered)} tools, assigning to agent {agent_id}")

    async with async_session() as db:
        assigned = 0
        for mcp_tool in tools_discovered:
            raw_name = mcp_tool.get("name", "")
            if not raw_name:
                continue

            tool_name = f"atlassian_rovo_{raw_name}"
            tool_desc = mcp_tool.get("description", "")[:500]
            tool_schema = mcp_tool.get("inputSchema", {"type": "object", "properties": {}})

            if "jira" in raw_name.lower() or "issue" in raw_name.lower():
                icon = "🔵"
            elif "confluence" in raw_name.lower() or "page" in raw_name.lower():
                icon = "📘"
            elif "compass" in raw_name.lower() or "component" in raw_name.lower():
                icon = "🧭"
            else:
                icon = "🔷"

            # Ensure Tool record exists (shared across all agents)
            tool_r = await db.execute(sa_select(Tool).where(Tool.name == tool_name))
            tool = tool_r.scalar_one_or_none()
            if not tool:
                tool = Tool(
                    name=tool_name,
                    display_name=f"Atlassian: {raw_name}",
                    description=tool_desc,
                    type="mcp",
                    category="atlassian",
                    icon=icon,
                    parameters_schema=tool_schema,
                    mcp_server_url=ATLASSIAN_MCP_URL,
                    mcp_server_name="Atlassian Rovo",
                    mcp_tool_name=raw_name,
                    enabled=True,
                    is_default=False,
                    source="admin",
                )
                db.add(tool)
                await db.flush()
            else:
                # Update schema in case it changed
                tool.description = tool_desc
                tool.parameters_schema = tool_schema

            # Assign to this specific agent (api_key stored per-agent via channel config,
            # but we also put it in AgentTool.config as fallback for _execute_mcp_tool)
            at_r = await db.execute(
                sa_select(AgentTool).where(
                    AgentTool.agent_id == agent_id,
                    AgentTool.tool_id == tool.id,
                )
            )
            at = at_r.scalar_one_or_none()
            if at:
                at.enabled = True
                at.config = {"api_key": api_key}
            else:
                db.add(AgentTool(
                    agent_id=agent_id,
                    tool_id=tool.id,
                    enabled=True,
                    source="user_installed",
                    installed_by_agent_id=agent_id,
                    config={"api_key": api_key},
                ))
                assigned += 1

        await db.commit()
    logger.info(f"[AtlassianChannel] {assigned} new tool assignments for agent {agent_id}")


async def get_atlassian_api_key_for_agent(agent_id: uuid.UUID, db=None) -> str | None:
    """Return the configured Atlassian API key for the given agent, or None."""
    from app.database import async_session

    async def _fetch(session):
        from app.core.security import decrypt_data
        from app.config import get_settings
        result = await session.execute(
            select(ChannelConfig).where(
                ChannelConfig.agent_id == agent_id,
                ChannelConfig.channel_type == "atlassian",
                ChannelConfig.is_configured == True,
            )
        )
        config = result.scalar_one_or_none()
        if not config or not config.app_secret:
            return None
        
        try:
            return decrypt_data(config.app_secret, get_settings().SECRET_KEY)
        except Exception:
            return config.app_secret

    if db is not None:
        return await _fetch(db)
    async with async_session() as session:
        return await _fetch(session)
