"""Ticker Registry service: add, delete, and list tracked tickers."""

import re

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

from app.exceptions import DuplicateError, NotFoundError, ValidationError
from app.models.ticker import Ticker


async def add_ticker(db: AsyncSession, symbol: str) -> Ticker:
    """Add a new ticker after validation.

    Validates: non-empty, uppercase alphanumeric. Auto-uppercases input.
    Raises DuplicateError if symbol already tracked.
    """
    stripped = symbol.strip()
    if not stripped:
        raise ValidationError("Ticker symbol must not be empty or whitespace-only")

    normalised = stripped.upper()
    if not re.fullmatch(r"[A-Z0-9]+", normalised):
        raise ValidationError(
            f"Ticker symbol must be alphanumeric: {normalised}"
        )

    result = await db.execute(select(Ticker).where(Ticker.symbol == normalised))
    if result.scalar_one_or_none() is not None:
        raise DuplicateError(f"Ticker already exists: {normalised}")

    ticker = Ticker(symbol=normalised)
    db.add(ticker)
    await db.commit()
    await db.refresh(ticker)
    return ticker


async def delete_ticker(db: AsyncSession, symbol: str) -> None:
    """Delete a ticker and cascade all associated data.

    Raises NotFoundError if the symbol is not tracked.
    """
    normalised = symbol.strip().upper()
    result = await db.execute(select(Ticker).where(Ticker.symbol == normalised))
    ticker = result.scalar_one_or_none()
    if ticker is None:
        raise NotFoundError(f"Ticker not found: {normalised}")

    await db.delete(ticker)
    await db.commit()


async def list_tickers(db: AsyncSession) -> list[Ticker]:
    """Return all tracked tickers sorted alphabetically by symbol."""
    result = await db.execute(select(Ticker).order_by(Ticker.symbol.asc()))
    return list(result.scalars().all())
