from fastapi import FastAPI, HTTPException

from app.adapters.iris import IrisAdapter
from app.adapters.pagerduty import PagerDutyAdapter
from app.adapters.shuffle import ShuffleAdapter
from app.adapters.wazuh import WazuhAdapter
from app.config import settings
from app.db import init_schema
from app.models import (
    ActionCreateIncidentRequest,
    ApiResponse,
    ShuffleLoginRequest,
    ShuffleProxyRequest,
    TriggerShuffleRequest,
    WazuhIngestRequest,
)
from app.repositories.mvp_repo import MvpRepository
from app.routes.mvp import build_mvp_router
from app.security import require_internal_api_key
from app.services.mvp_service import MvpService

app = FastAPI(title=settings.app_name, version="0.1.0")

wazuh_adapter = WazuhAdapter(
    base_url=settings.wazuh_base_url,
    username=settings.wazuh_username,
    password=settings.wazuh_password,
)
shuffle_adapter = ShuffleAdapter(
    base_url=settings.shuffle_base_url,
    api_key=settings.shuffle_api_key,
)
pagerduty_adapter = PagerDutyAdapter(
    base_url=settings.pagerduty_base_url,
    api_key=settings.pagerduty_api_key,
)
iris_adapter = IrisAdapter(
    base_url=settings.iris_base_url,
    api_key=settings.iris_api_key,
)

repo = MvpRepository()
mvp_service = MvpService(
    repo=repo,
    wazuh_adapter=wazuh_adapter,
    shuffle_adapter=shuffle_adapter,
    iris_adapter=iris_adapter,
    pagerduty_adapter=pagerduty_adapter,
)
app.include_router(build_mvp_router(mvp_service, require_internal_api_key))


@app.on_event("startup")
async def startup() -> None:
    init_schema()
    repo.ensure_policy()


@app.get("/health", response_model=ApiResponse)
async def health() -> ApiResponse:
    return ApiResponse(
        data={
            "service": settings.app_name,
            "env": settings.app_env,
            "targets": {
                "wazuh": settings.wazuh_base_url,
                "shuffle": settings.shuffle_base_url,
                "pagerduty": settings.pagerduty_base_url,
                "iris": settings.iris_base_url,
            },
        }
    )


@app.post("/ingest/wazuh-alert", response_model=ApiResponse)
async def ingest_wazuh_alert(payload: WazuhIngestRequest) -> ApiResponse:
    normalized = {
        "source": payload.source,
        "alert_id": payload.alert_id,
        "rule_id": payload.rule_id,
        "severity": payload.severity,
        "title": payload.title,
        "payload": payload.payload,
    }
    return ApiResponse(data={"normalized": normalized})


@app.post("/action/create-incident", response_model=ApiResponse)
async def create_incident(payload: ActionCreateIncidentRequest) -> ApiResponse:
    incident_payload = {
        "title": payload.title,
        "urgency": payload.severity,
        "incident_key": payload.dedupe_key,
        "body": payload.payload,
        "source": payload.source,
    }
    try:
        pd_result = await pagerduty_adapter.create_incident(incident_payload)
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"PagerDuty call failed: {exc}") from exc
    return ApiResponse(data={"pagerduty": pd_result})


@app.post("/action/trigger-shuffle", response_model=ApiResponse)
async def trigger_shuffle(payload: TriggerShuffleRequest) -> ApiResponse:
    try:
        shuffle_result = await shuffle_adapter.trigger_workflow(
            workflow_id=payload.workflow_id,
            payload=payload.execution_argument,
        )
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Shuffle call failed: {exc}") from exc
    return ApiResponse(data={"shuffle": shuffle_result})


@app.get("/shuffle/health", response_model=ApiResponse)
async def shuffle_health() -> ApiResponse:
    try:
        result = await shuffle_adapter.health()
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Shuffle call failed: {exc}") from exc
    return ApiResponse(data={"shuffle": result})


@app.get("/shuffle/auth-test", response_model=ApiResponse)
async def shuffle_auth_test() -> ApiResponse:
    try:
        result = await shuffle_adapter.auth_test()
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Shuffle call failed: {exc}") from exc
    return ApiResponse(data={"shuffle": result})


@app.post("/shuffle/login", response_model=ApiResponse)
async def shuffle_login(payload: ShuffleLoginRequest) -> ApiResponse:
    try:
        result = await shuffle_adapter.login(payload.username, payload.password)
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Shuffle call failed: {exc}") from exc
    return ApiResponse(data={"shuffle": result})


@app.post("/shuffle/generate-apikey", response_model=ApiResponse)
async def shuffle_generate_apikey(payload: ShuffleLoginRequest | None = None) -> ApiResponse:
    username = payload.username if payload else settings.shuffle_username
    password = payload.password if payload else settings.shuffle_password
    if not username or not password:
        raise HTTPException(
            status_code=400,
            detail="Missing shuffle credentials. Provide username/password in body or set SHUFFLE_USERNAME and SHUFFLE_PASSWORD.",
        )

    try:
        result = await shuffle_adapter.generate_apikey_from_login(username, password)
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Shuffle call failed: {exc}") from exc
    return ApiResponse(data={"shuffle": result})


@app.get("/shuffle/workflows", response_model=ApiResponse)
async def shuffle_workflows() -> ApiResponse:
    try:
        result = await shuffle_adapter.list_workflows()
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Shuffle call failed: {exc}") from exc
    return ApiResponse(data={"shuffle": result})


@app.get("/shuffle/workflows/{workflow_id}", response_model=ApiResponse)
async def shuffle_workflow(workflow_id: str) -> ApiResponse:
    try:
        result = await shuffle_adapter.get_workflow(workflow_id)
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Shuffle call failed: {exc}") from exc
    return ApiResponse(data={"shuffle": result})


@app.post("/shuffle/workflows/{workflow_id}/execute", response_model=ApiResponse)
async def shuffle_workflow_execute(
    workflow_id: str, payload: dict[str, object]
) -> ApiResponse:
    try:
        result = await shuffle_adapter.trigger_workflow(workflow_id=workflow_id, payload=payload)
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Shuffle call failed: {exc}") from exc
    return ApiResponse(data={"shuffle": result})


@app.get("/shuffle/apps", response_model=ApiResponse)
async def shuffle_apps() -> ApiResponse:
    try:
        result = await shuffle_adapter.list_apps()
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Shuffle call failed: {exc}") from exc
    return ApiResponse(data={"shuffle": result})


@app.post("/shuffle/proxy", response_model=ApiResponse)
async def shuffle_proxy(payload: ShuffleProxyRequest) -> ApiResponse:
    path = payload.path if payload.path.startswith("/api/") else f"/api/v1/{payload.path.lstrip('/')}"
    try:
        result = await shuffle_adapter.proxy(
            method=payload.method,
            path=path,
            params=payload.params,
            payload=payload.payload,
        )
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Shuffle call failed: {exc}") from exc
    return ApiResponse(data={"shuffle": result})


@app.post("/action/create-iris-case", response_model=ApiResponse)
async def create_iris_case(payload: ActionCreateIncidentRequest) -> ApiResponse:
    # IRIS v2 expects case_name, case_description, case_customer, case_soc_id.
    case_payload = {
        "case_name": payload.title,
        "case_description": payload.payload.get("description", "Created by soc-integrator"),
        "case_customer": payload.payload.get("case_customer", settings.iris_default_customer_id),
        "case_soc_id": payload.payload.get("case_soc_id", settings.iris_default_soc_id),
    }
    try:
        iris_result = await iris_adapter.create_case(case_payload)
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"IRIS call failed: {exc}") from exc
    return ApiResponse(data={"iris": iris_result})


@app.get("/sync/wazuh-version", response_model=ApiResponse)
async def sync_wazuh_version() -> ApiResponse:
    try:
        wazuh_result = await wazuh_adapter.get_version()
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Wazuh call failed: {exc}") from exc
    return ApiResponse(data={"wazuh": wazuh_result})


@app.get("/wazuh/auth-test", response_model=ApiResponse)
async def wazuh_auth_test() -> ApiResponse:
    try:
        result = await wazuh_adapter.auth_test()
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Wazuh auth failed: {exc}") from exc
    return ApiResponse(data={"wazuh": result})


@app.get("/wazuh/manager-info", response_model=ApiResponse)
async def wazuh_manager_info() -> ApiResponse:
    try:
        result = await wazuh_adapter.get_manager_info()
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Wazuh call failed: {exc}") from exc
    return ApiResponse(data={"wazuh": result})


@app.get("/wazuh/agents", response_model=ApiResponse)
async def wazuh_agents(
    limit: int = 50,
    offset: int = 0,
    select: str | None = None,
) -> ApiResponse:
    try:
        result = await wazuh_adapter.list_agents(limit=limit, offset=offset, select=select)
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Wazuh call failed: {exc}") from exc
    return ApiResponse(data={"wazuh": result})


@app.get("/wazuh/alerts", response_model=ApiResponse)
async def wazuh_alerts(
    limit: int = 50,
    offset: int = 0,
    q: str | None = None,
    sort: str | None = None,
) -> ApiResponse:
    try:
        # In this Wazuh build, API alerts are exposed via manager logs.
        result = await wazuh_adapter.list_manager_logs(
            limit=limit, offset=offset, q=q, sort=sort
        )
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Wazuh call failed: {exc}") from exc
    return ApiResponse(data={"wazuh": result})


@app.get("/wazuh/manager-logs", response_model=ApiResponse)
async def wazuh_manager_logs(
    limit: int = 50,
    offset: int = 0,
    q: str | None = None,
    sort: str | None = None,
) -> ApiResponse:
    try:
        result = await wazuh_adapter.list_manager_logs(
            limit=limit, offset=offset, q=q, sort=sort
        )
    except Exception as exc:
        raise HTTPException(status_code=502, detail=f"Wazuh call failed: {exc}") from exc
    return ApiResponse(data={"wazuh": result})
