# uuid=53cd37cc-4563-47bf-b278-832e09df45b3
# version=1

if version\0 < 1:

    from llm import agent

    type User:
        var name
        var default_channel
        one have_met                -- N/A or true

    type Channel:
        var active_thread

    type Thread:
        val channel
        val messages                -- List of messages in order

    type Message:
        val from                    -- User who sent it
        val when                    -- when they sent it
        val text                    -- what they sent
        val channel                 -- Channel it was sent to
        one thread                  -- Thread; N/A until assigned to a thread.  Most useful to find threads from direct replies.
        val in_reply_to             -- Message it was in explicit reply to if applicable

    def format_message(m):
        -- print("FORMAT_MESSAGE: m.when={m.when} m.from={m.from.name} m.text={m.text}")
        return "[{format_time(m.when)}] {m.from.name}: {m.text}"

    def format_messages(l): -- l is a list of messages
        return joinlines([format_message(m) for m in l])

    ------ Outgoing messages -------

    import telegram -- Will eventually dispatch on channel type, but for now hard-coded to Telegram
    def send_message_to_channel(chan, text):
        return telegram.send_message_to_telegram_channel(chan, text)

    def send_message_to_thread(thread, text):
        m = send_message_to_channel(thread.channel, text)
        m.thread = thread
        append(thread.messages, m)

    ------ Incoming messages -------

    {|
     | Wait for one or more (usually just one) message to come in on a thread.
     |}
    def wait_for_new_messages_on_thread(thread):
        q   = thread.messages
        ref = length(q)
        wait until length(q) > ref

    {|
     | Dispatch a Message to a Thread.
     |}
    def dispatch_message_to_thread(m, thread):
        print("CHANNELS: Dispatching message {m} to thread {thread}")
        m.thread = thread
        append(thread.messages, m)

    {|
     | Dispatch a Message to the Channel it belongs to.
     |}
    def dispatch_message_to_channel(m, chan):

        print("CHANNELS: Dispatching message {m} to channel {chan}")

        (|
         | try to dispatch direct replies to the thread that owned the message being replied to:
         |)
        if (thread = m.in_reply_to.thread)?:
            -- FIXME: This is problematic as the thread may be closed; more work needs to be done here.
            print("CHANNELS: Routing to direct-reply thread {thread}")
            dispatch_message_to_thread(m, thread)

        (|
         | try to dispatch to the active/owning thread for this channel, if applicable:
         |)
        else if (thread = chan.active_thread)?:
            print("CHANNELS: Routing to currently active thread {thread}")
            dispatch_message_to_thread(m, thread)

        (|
         | Initiate a new thread
         |)
        else:
            print("CHANNELS: Creating new thread")
            thread = m.thread = chan.active_thread = Thread(channel=chan, messages=[m])
            spawn dispatch_new_thread(thread, m.from)

    {|
     | Decide what the goal of a new thread is, and invoke that goal.
     |}
    def dispatch_new_thread(thread, user):

        from skills import things_I_can_do

        msg = $"Which goal should we direct this new user thread to?

                User thread:
                    {format_messages(thread.messages)}

                Available goals:
                    {joinlines(["[{i}] {goal.summary}" for i:goal in things_I_can_do])}

                If one of those goals sounds applicable, reply with action=<the number of the applicable goal>

                If none of those goals sounds applicable reply with action=-1
                "$

        option = agent(msg).action

        if not (goal = things_I_can_do[option])?:
            send_message_to_thread(thread, "I have no response to that.")
            thread.channel.active_thread = none
            return

        spawn:
            goal(thread, user)
            print("CHANNELS: {goal} completed.  Releasing channel.")
            thread.channel.active_thread = none