"""The cards offered on the new-chat screen.

A blank composer is the least helpful thing a chat client can show someone who
has just installed one. These are three starting points an administrator can
replace with their own.
"""

from __future__ import annotations

import logging

from sqlalchemy import func, select
from sqlalchemy.orm import Session as DBSession

from lembas.db.models import Suggestion
from lembas.services import settings_store

log = logging.getLogger(__name__)

# A short list stays a short list. Past a dozen it is a menu, and a menu on the
# empty screen is a worse blank page than a blank page.
MAX_SUGGESTIONS = 12
MAX_SHOWN = 6

MAX_NAME = 120
MAX_DESCRIPTION = 300
MAX_PROMPT = 4000

# A card is sent the moment it is clicked, so each of these has to work cold --
# with nothing pasted and nothing typed. These four are *self-contained* rather
# than question-asking: they are what somebody clicks on an instance they have
# just stood up, to find out whether the thing works and what the model behind
# it is. That is the honest first use, and it is a different job from the task
# cards that preceded them, which opened by asking for material the reader had
# not given.
#
# The name and description are read by somebody who has never seen this
# instance; the prompt is read by the model. They are allowed to differ, and
# here they do -- "Start a session" says what the card is for, and its prompt is
# the bare line that produces a clean opening turn.
#
# Only a fresh install gets these: `SEEDED_KEY` means an instance that has
# already seeded keeps whatever its administrator has since made of the list.
#
# No Middle-earth flavour: this is functional UI.
DEFAULTS: tuple[tuple[str, str, str], ...] = (
    (
        "Start a session",
        "Open a fresh conversation with nothing assumed.",
        "Initializing a new session.",
    ),
    (
        "What can you do?",
        "Have the model say which tools, instructions and limits it has.",
        "Who are you and what are you capable of? What are your available tools? "
        "What do you already know from your instructions? Do you have any set "
        "personality?",
    ),
    (
        "Show me some code",
        "See how the model writes, in a language of its own choosing.",
        "Pick a random programming language and produce a coding example showing "
        "your coding capabilities.",
    ),
    (
        "Tell me something",
        "A fact worth knowing, from a subject picked at random.",
        "Give me a random fun fact from a random topic of your choosing. "
        "Available topics are science, history, sociology, theology etc.",
    ),
)

# Guards the seed. Not "is the table empty", because an administrator who
# deletes all three would get them back on every restart.
SEEDED_KEY = "suggestions_seeded"


def visible(db: DBSession) -> list[Suggestion]:
    """What the new-chat screen shows, in order."""
    return list(
        db.scalars(
            select(Suggestion)
            .where(Suggestion.enabled.is_(True))
            .order_by(Suggestion.position, Suggestion.name)
            .limit(MAX_SHOWN)
        )
    )


def all_of_them(db: DBSession) -> list[Suggestion]:
    """Every suggestion, enabled or not, for the admin page."""
    return list(
        db.scalars(select(Suggestion).order_by(Suggestion.position, Suggestion.name))
    )


def next_position(db: DBSession) -> int:
    """New rows land at the end rather than at 0, where they would shuffle.

    No `or -1` after the coalesce: position 0 is falsy, so that idiom sends the
    second row back to 0 on top of the first.
    """
    highest = db.scalar(select(func.coalesce(func.max(Suggestion.position), -1)))
    return int(highest if highest is not None else -1) + 1


def create(db: DBSession, *, name: str, description: str = "", prompt: str = "") -> Suggestion:
    suggestion = Suggestion(
        name=name.strip()[:MAX_NAME],
        description=description.strip()[:MAX_DESCRIPTION],
        prompt=prompt[:MAX_PROMPT],
        position=next_position(db),
    )
    db.add(suggestion)
    db.commit()
    return suggestion


def seed_defaults(db: DBSession) -> int:
    """Write the built-in suggestions, once ever.

    Runs from the startup housekeeping block. The flag is what makes it once:
    checking whether the table is empty would restore all three every restart
    for anyone who decided they did not want them.
    """
    if settings_store.get(db, SEEDED_KEY):
        return 0

    for name, description, prompt in DEFAULTS:
        create(db, name=name, description=description, prompt=prompt)

    settings_store.update(db, {SEEDED_KEY: True})
    log.info("seeded %d default suggestion(s)", len(DEFAULTS))
    return len(DEFAULTS)
