"""Business logic for information fields."""
from __future__ import annotations

from typing import List, Literal, Optional
from uuid import UUID

from fastapi import HTTPException
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from normbase.models.norm import Field as InfoField


class FieldService:
    """Service layer for information field operations."""

    async def list_fields(
        self,
        db: AsyncSession,
        status_filter: Optional[Literal["active", "inactive", "archived"]] = None,
    ) -> List[InfoField]:
        stmt = select(InfoField).order_by(InfoField.created_at.desc())
        if status_filter is not None:
            stmt = stmt.where(InfoField.status == status_filter)
        return (await db.execute(stmt)).scalars().all()

    async def create_field(
        self,
        db: AsyncSession,
        *,
        name: str,
        description: Optional[str],
        org_id: Optional[UUID],
        status_value: Literal["active", "inactive", "archived"],
    ) -> InfoField:
        normalized_name = (name or "").strip()
        if not normalized_name:
            raise HTTPException(status_code=400, detail="Field name cannot be empty.")

        existing_stmt = select(InfoField).where(InfoField.name == normalized_name)
        existing = (await db.execute(existing_stmt)).scalar_one_or_none()
        if existing:
            raise HTTPException(status_code=409, detail=f"Field '{normalized_name}' already exists.")

        item = InfoField(
            name=normalized_name,
            description=(description or None),
            org_id=org_id,
            status=status_value,
        )
        db.add(item)
        await db.commit()
        await db.refresh(item)
        return item

    async def update_field(
        self,
        db: AsyncSession,
        *,
        field_id: UUID,
        name: Optional[str],
        description: Optional[str],
        org_id: Optional[UUID],
        status_value: Optional[Literal["active", "inactive", "archived"]],
    ) -> InfoField:
        item = (
            await db.execute(select(InfoField).where(InfoField.id == field_id))
        ).scalar_one_or_none()
        if item is None:
            raise HTTPException(status_code=404, detail="Field not found.")

        if name is not None:
            normalized_name = name.strip()
            if not normalized_name:
                raise HTTPException(status_code=400, detail="Field name cannot be empty.")
            existing_stmt = select(InfoField).where(
                InfoField.name == normalized_name,
                InfoField.id != field_id,
            )
            existing = (await db.execute(existing_stmt)).scalar_one_or_none()
            if existing:
                raise HTTPException(status_code=409, detail=f"Field '{normalized_name}' already exists.")
            item.name = normalized_name

        if description is not None:
            item.description = description
        if org_id is not None:
            item.org_id = org_id
        if status_value is not None:
            item.status = status_value

        await db.commit()
        await db.refresh(item)
        return item

    async def soft_delete_field(self, db: AsyncSession, *, field_id: UUID) -> InfoField:
        item = (
            await db.execute(select(InfoField).where(InfoField.id == field_id))
        ).scalar_one_or_none()
        if item is None:
            raise HTTPException(status_code=404, detail="Field not found.")

        item.status = "archived"
        await db.commit()
        await db.refresh(item)
        return item
