"""Process Core-owned external-admin assistant chat jobs."""
from __future__ import annotations

import secrets
from datetime import datetime, timedelta, timezone
from typing import Optional
from uuid import UUID

import structlog

from src.core.database import async_session_factory
from src.domain.external_admin.models import (
    ACTION_SESSION_STATUS_PENDING,
    CHAT_JOB_STATUS_COMPLETED,
    CHAT_JOB_STATUS_FAILED,
    CHAT_JOB_STATUS_PENDING,
    CHAT_JOB_STATUS_RUNNING,
    AssistantActionSession,
    ExternalAdminChatMessage,
)
from src.domain.external_admin.repository import (
    AssistantActionSessionRepository,
    ExternalAdminChatJobRepository,
    ExternalAdminChatMessageRepository,
    ExternalAdminInstallationRepository,
)
from src.domain.external_admin.chat_context import build_external_admin_chat_context
from src.domain.external_admin.wp_chat_ai import call_wp_chat_ai

logger = structlog.get_logger()

_ACTION_SESSION_TTL_HOURS = 24


async def process_external_admin_chat_job(ctx: dict, job_id: str) -> dict:
    """Run a persisted external-admin chat job through Core AI orchestration.

    Loads site context (latest Site Understanding, Cloud D1 shape, conversation
    history) and calls the configured AI provider via call_wp_chat_ai(), which
    routes through the same get_ai_provider() factory used by all Core codegen
    operations (AI_PROVIDER env var: openai | claude | cursor).

    For mutation requests the AI embeds a structured plan; Core creates an
    AssistantActionSession for the site owner to approve before execution.
    """
    db_factory = ctx.get("db_factory", async_session_factory)
    try:
        chat_job_id = UUID(job_id)
    except ValueError:
        logger.warning("external_admin_chat_invalid_job_id", job_id=job_id)
        return {"status": "invalid_job_id"}

    async with db_factory() as db:
        job_repo = ExternalAdminChatJobRepository(db)
        job = await job_repo.get(chat_job_id)
        if not job:
            logger.warning("external_admin_chat_job_not_found", job_id=job_id)
            return {"status": "not_found"}
        if job.status == CHAT_JOB_STATUS_COMPLETED:
            return {"status": "already_completed"}
        if job.status not in (CHAT_JOB_STATUS_PENDING, CHAT_JOB_STATUS_FAILED):
            return {"status": job.status}

        job.status = CHAT_JOB_STATUS_RUNNING
        await job_repo.save(job)
        await db.commit()

    try:
        async with db_factory() as db:
            job_repo = ExternalAdminChatJobRepository(db)
            message_repo = ExternalAdminChatMessageRepository(db)
            action_session_repo = AssistantActionSessionRepository(db)

            job = await job_repo.get(chat_job_id)
            if not job:
                return {"status": "not_found"}

            installation = await ExternalAdminInstallationRepository(db).get_by_id(job.installation_id)
            if not installation:
                raise RuntimeError("installation_not_found")

            context = await build_external_admin_chat_context(
                db,
                installation_id=job.installation_id,
                session_id=job.session_id,
            )

            # Call the configured AI provider (Claude / OpenAI / Cursor-fallback).
            # wp_chat_ai handles provider selection, prompt formatting, and response parsing.
            assistant_content, plan, run_class = await call_wp_chat_ai(context)

            action_session: Optional[AssistantActionSession] = None
            if plan and isinstance(plan.get("operations"), list) and plan["operations"]:
                action_session = AssistantActionSession(
                    project_id=installation.project_id,
                    installation_id=installation.id,
                    correlation_id=secrets.token_hex(16),
                    action=f"{installation.installation_type}_{plan.get('run_class', 'mutation')}",
                    status=ACTION_SESSION_STATUS_PENDING,
                    payload=plan,
                    expires_at=datetime.now(timezone.utc) + timedelta(hours=_ACTION_SESSION_TTL_HOURS),
                )
                await action_session_repo.create(action_session)

            assistant_message = ExternalAdminChatMessage(
                session_id=job.session_id,
                installation_id=job.installation_id,
                role="assistant",
                content=assistant_content,
            )
            await message_repo.create(assistant_message)

            job.status = CHAT_JOB_STATUS_COMPLETED
            job.assistant_message_id = assistant_message.id
            job.action_session_id = action_session.id if action_session else None
            job.run_class = run_class
            job.context_json = {
                "site_understanding_status": (context.get("site_understanding") or {}).get("status"),
                "cloud_site_shape_status": (context.get("cloud_site_shape") or {}).get("status"),
            }
            job.result_json = {
                "run_class": run_class,
                "action_session_id": str(action_session.id) if action_session else None,
                "operations_proposed": len(plan.get("operations", [])) if plan else 0,
            }
            job.error = None
            await job_repo.save(job)
            await db.commit()

        logger.info("external_admin_chat_job_completed", job_id=job_id, run_class=run_class)
        return {"status": CHAT_JOB_STATUS_COMPLETED, "run_class": run_class}

    except Exception as exc:
        logger.exception("external_admin_chat_job_failed", job_id=job_id, error=str(exc))
        async with db_factory() as db:
            job_repo = ExternalAdminChatJobRepository(db)
            job = await job_repo.get(chat_job_id)
            if job:
                job.status = CHAT_JOB_STATUS_FAILED
                job.error = str(exc)[:500]
                await job_repo.save(job)
                await db.commit()
        return {"status": CHAT_JOB_STATUS_FAILED}
