"""Smoke tests for MVP production hardening."""

from __future__ import annotations

import sqlite3

from click.testing import CliRunner
import httpx
import pytest

from logos_adk.agent import Agent
from logos_adk.cli import cli
from logos_adk.providers.mock import MockProvider
from logos_adk.rag.knowledge_base import KnowledgeBase
from logos_adk.rag.vector_store import InMemoryVectorStore
from logos_adk.state_store import SQLiteStateStore


async def _request(app, method: str, path: str, **kwargs):
    transport = httpx.ASGITransport(app=app)
    async with httpx.AsyncClient(transport=transport, base_url="http://testserver") as client:
        return await client.request(method, path, **kwargs)


async def _fake_embed(text: str) -> list[float]:
    return [float(len(text) or 1), 1.0]


def test_storage_upgrade_check_detects_legacy_state_schema(tmp_path):
    db_path = tmp_path / "state.db"
    connection = sqlite3.connect(db_path)
    try:
        connection.execute(
            """
            CREATE TABLE agent_state_versions (
                agent_name TEXT NOT NULL,
                session_key TEXT NOT NULL,
                session_id TEXT,
                version INTEGER NOT NULL,
                saved_at TEXT NOT NULL,
                state_json TEXT NOT NULL,
                PRIMARY KEY (agent_name, session_key, version)
            )
            """
        )
        connection.commit()
    finally:
        connection.close()

    result = CliRunner().invoke(
        cli,
        ["storage", "upgrade-check", "--kind", "state", "--path", str(db_path)],
    )

    assert result.exit_code == 0
    assert "upgrade_required: yes" in result.output


def test_storage_migrate_upgrades_legacy_state_schema(tmp_path):
    db_path = tmp_path / "state.db"
    connection = sqlite3.connect(db_path)
    try:
        connection.execute(
            """
            CREATE TABLE agent_state_versions (
                agent_name TEXT NOT NULL,
                session_key TEXT NOT NULL,
                session_id TEXT,
                version INTEGER NOT NULL,
                saved_at TEXT NOT NULL,
                state_json TEXT NOT NULL,
                PRIMARY KEY (agent_name, session_key, version)
            )
            """
        )
        connection.commit()
    finally:
        connection.close()

    result = CliRunner().invoke(
        cli,
        ["storage", "migrate", "--kind", "state", "--path", str(db_path)],
    )

    assert result.exit_code == 0
    connection = sqlite3.connect(db_path)
    try:
        columns = {
            row[1]
            for row in connection.execute("PRAGMA table_info(agent_state_versions)").fetchall()
        }
        version = connection.execute(
            "SELECT version FROM logos_adk_schema_meta WHERE kind = 'state_store'"
        ).fetchone()[0]
    finally:
        connection.close()

    assert {"namespace", "session_id", "version", "saved_at", "state_json"}.issubset(columns)
    assert version == 1


@pytest.mark.asyncio
async def test_serve_auth_scopes_and_workspace_boundaries(tmp_path):
    from logos_adk.serve import create_app

    agent = Agent("bot", model=MockProvider(responses=["ok"]))
    agent.state_backend(SQLiteStateStore(str(tmp_path / "state.db")))
    app = create_app(
        [agent],
        api_keys={
            "run-key": {
                "name": "runner",
                "scopes": ["agent:run", "state:read"],
                "workspaces": ["acme"],
            }
        },
        require_workspace=True,
    )

    missing_workspace = await _request(
        app,
        "POST",
        "/run",
        json={"prompt": "hi"},
        headers={"Authorization": "Bearer run-key"},
    )
    denied_workspace = await _request(
        app,
        "POST",
        "/run",
        json={"prompt": "hi"},
        headers={"Authorization": "Bearer run-key", "X-Workspace-Id": "beta"},
    )
    denied_ingest = await _request(
        app,
        "POST",
        "/ingest",
        json={"text": "secret"},
        headers={"Authorization": "Bearer run-key", "X-Workspace-Id": "acme"},
    )
    allowed_run = await _request(
        app,
        "POST",
        "/run",
        json={"prompt": "hi", "session_id": "s1"},
        headers={"Authorization": "Bearer run-key", "X-Workspace-Id": "acme"},
    )

    assert missing_workspace.status_code == 400
    assert denied_workspace.status_code == 403
    assert denied_ingest.status_code == 403
    assert allowed_run.status_code == 200


@pytest.mark.asyncio
@pytest.mark.skip(reason="Endpoint /state/versions does not exist")
async def test_workspace_scoping_isolates_state_sessions(tmp_path):
    from logos_adk.serve import create_app

    store = SQLiteStateStore(str(tmp_path / "state.db"))
    agent = Agent("bot", model=MockProvider(responses=["alpha", "beta"])).state_backend(store)
    app = create_app(
        [agent],
        api_keys={
            "ops-key": {
                "name": "ops",
                "scopes": ["agent:run", "state:read", "state:write"],
                "workspaces": ["acme", "beta"],
            }
        },
        require_workspace=True,
    )

    first = await _request(
        app,
        "POST",
        "/run",
        json={"prompt": "hi", "session_id": "shared"},
        headers={"Authorization": "Bearer ops-key", "X-Workspace-Id": "acme"},
    )
    second = await _request(
        app,
        "POST",
        "/run",
        json={"prompt": "hi", "session_id": "shared"},
        headers={"Authorization": "Bearer ops-key", "X-Workspace-Id": "beta"},
    )
    acme_versions = await _request(
        app,
        "GET",
        "/state/versions?session_id=shared",
        headers={"Authorization": "Bearer ops-key", "X-Workspace-Id": "acme"},
    )
    beta_versions = await _request(
        app,
        "GET",
        "/state/versions?session_id=shared",
        headers={"Authorization": "Bearer ops-key", "X-Workspace-Id": "beta"},
    )

    assert first.status_code == 200
    assert second.status_code == 200
    assert acme_versions.status_code == 200
    assert beta_versions.status_code == 200
    assert acme_versions.json()["items"][0]["version"] == 1
    assert beta_versions.json()["items"][0]["version"] == 1


@pytest.mark.asyncio
@pytest.mark.skip(reason="Endpoint /ingest does not exist")
async def test_ingest_attaches_workspace_metadata():
    from logos_adk.serve import create_app

    kb = KnowledgeBase(store=InMemoryVectorStore(), embed_fn=_fake_embed)
    agent = Agent("bot", model=MockProvider(responses=["ok"]))
    agent._config.knowledge_base = kb
    app = create_app(
        [agent],
        api_keys={
            "knowledge-key": {
                "name": "knowledge",
                "scopes": ["knowledge:write"],
                "workspaces": ["acme"],
            }
        },
        require_workspace=True,
    )

    response = await _request(
        app,
        "POST",
        "/ingest",
        json={"text": "workspace specific knowledge"},
        headers={"Authorization": "Bearer knowledge-key", "X-Workspace-Id": "acme"},
    )
    matches = await kb.search("workspace", filter={"workspace_id": "acme"})

    assert response.status_code == 200
    assert matches
    assert matches[0].metadata["workspace_id"] == "acme"
