"""
Script Flow Service for AI Service.
[AC-AISVC-71, AC-AISVC-72, AC-AISVC-73] Flow definition CRUD operations.
"""

import logging
import uuid
from collections.abc import Sequence
from datetime import datetime
from typing import Any

from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import col

from app.models.entities import (
    ScriptFlow,
    ScriptFlowCreate,
    ScriptFlowUpdate,
)

logger = logging.getLogger(__name__)


class ScriptFlowService:
    """
    [AC-AISVC-71~AC-AISVC-73] Service for managing script flow definitions.

    Features:
    - Flow CRUD with tenant isolation
    - Step validation
    - Linked intent rule count tracking
    """

    def __init__(self, session: AsyncSession):
        self._session = session

    async def create_flow(
        self,
        tenant_id: str,
        create_data: ScriptFlowCreate,
    ) -> ScriptFlow:
        """
        [AC-AISVC-71] Create a new script flow with steps.
        [AC-IDSMETA-16] Support metadata field.
        """
        self._validate_steps(create_data.steps)

        flow = ScriptFlow(
            tenant_id=tenant_id,
            name=create_data.name,
            description=create_data.description,
            steps=create_data.steps,
            is_enabled=create_data.is_enabled,
            metadata_=create_data.metadata_,
        )
        self._session.add(flow)
        await self._session.flush()

        logger.info(
            f"[AC-AISVC-71][AC-IDSMETA-16] Created script flow: tenant={tenant_id}, "
            f"id={flow.id}, name={flow.name}, steps={len(flow.steps)}"
        )
        return flow

    async def list_flows(
        self,
        tenant_id: str,
        is_enabled: bool | None = None,
    ) -> Sequence[ScriptFlow]:
        """
        [AC-AISVC-72] List flows for a tenant, optionally filtered by enabled status.
        """
        stmt = select(ScriptFlow).where(
            ScriptFlow.tenant_id == tenant_id
        )

        if is_enabled is not None:
            stmt = stmt.where(ScriptFlow.is_enabled == is_enabled)

        stmt = stmt.order_by(col(ScriptFlow.created_at).desc())
        result = await self._session.execute(stmt)
        return result.scalars().all()

    async def get_flow(
        self,
        tenant_id: str,
        flow_id: uuid.UUID,
    ) -> ScriptFlow | None:
        """
        Get flow by ID with tenant isolation.
        """
        stmt = select(ScriptFlow).where(
            ScriptFlow.tenant_id == tenant_id,
            ScriptFlow.id == flow_id,
        )
        result = await self._session.execute(stmt)
        return result.scalar_one_or_none()

    async def get_flow_detail(
        self,
        tenant_id: str,
        flow_id: uuid.UUID,
    ) -> dict[str, Any] | None:
        """
        [AC-AISVC-73] Get flow detail with complete step definitions.
        [AC-IDSMETA-16] Include metadata field.
        """
        flow = await self.get_flow(tenant_id, flow_id)
        if not flow:
            return None

        linked_rule_count = await self._get_linked_rule_count(tenant_id, flow_id)

        return {
            "id": str(flow.id),
            "name": flow.name,
            "description": flow.description,
            "steps": flow.steps,
            "is_enabled": flow.is_enabled,
            "step_count": len(flow.steps),
            "linked_rule_count": linked_rule_count,
            "metadata": flow.metadata_,
            "created_at": flow.created_at.isoformat(),
            "updated_at": flow.updated_at.isoformat(),
        }

    async def update_flow(
        self,
        tenant_id: str,
        flow_id: uuid.UUID,
        update_data: ScriptFlowUpdate,
    ) -> ScriptFlow | None:
        """
        [AC-AISVC-73] Update flow definition.
        [AC-IDSMETA-16] Support metadata field.
        """
        flow = await self.get_flow(tenant_id, flow_id)
        if not flow:
            return None

        if update_data.name is not None:
            flow.name = update_data.name
        if update_data.description is not None:
            flow.description = update_data.description
        if update_data.steps is not None:
            self._validate_steps(update_data.steps)
            flow.steps = update_data.steps
        if update_data.is_enabled is not None:
            flow.is_enabled = update_data.is_enabled
        if update_data.metadata_ is not None:
            flow.metadata_ = update_data.metadata_
        flow.updated_at = datetime.utcnow()

        await self._session.flush()

        logger.info(
            f"[AC-AISVC-73][AC-IDSMETA-16] Updated script flow: tenant={tenant_id}, id={flow_id}"
        )
        return flow

    async def delete_flow(
        self,
        tenant_id: str,
        flow_id: uuid.UUID,
    ) -> bool:
        """Delete a flow definition."""
        flow = await self.get_flow(tenant_id, flow_id)
        if not flow:
            return False

        await self._session.delete(flow)
        await self._session.flush()

        logger.info(
            f"Deleted script flow: tenant={tenant_id}, id={flow_id}"
        )
        return True

    async def get_step_count(
        self,
        tenant_id: str,
        flow_id: uuid.UUID,
    ) -> int:
        """Get the number of steps in a flow."""
        flow = await self.get_flow(tenant_id, flow_id)
        return len(flow.steps) if flow else 0

    async def _get_linked_rule_count(
        self,
        tenant_id: str,
        flow_id: uuid.UUID,
    ) -> int:
        """Get count of intent rules linked to this flow."""
        from app.models.entities import IntentRule

        stmt = select(func.count()).select_from(IntentRule).where(
            IntentRule.tenant_id == tenant_id,
            IntentRule.flow_id == flow_id,
        )
        result = await self._session.execute(stmt)
        return result.scalar() or 0

    def _validate_steps(self, steps: list[dict[str, Any]]) -> None:
        """Validate step definitions."""
        if not steps:
            raise ValueError("Flow must have at least one step")

        step_nos = set()
        for step in steps:
            step_no = step.get("step_no")
            if step_no is None:
                raise ValueError("Each step must have a step_no")
            if step_no in step_nos:
                raise ValueError(f"Duplicate step_no: {step_no}")
            step_nos.add(step_no)

            if not step.get("content"):
                raise ValueError(f"Step {step_no} must have content")

            next_conditions = step.get("next_conditions", [])
            for cond in next_conditions:
                if cond.get("goto_step") is None:
                    raise ValueError(f"next_condition in step {step_no} must have goto_step")
