/**
 * Chat Store – V2 Dashboard
 *
 * Fetches the OpenClaw-backed session history and sends new messages through
 * the authenticated Nexus -> OpenClaw -> model runtime path.
 *
 * Auto-refresh: every 10 seconds (incoming Iris messages).
 */
import { defineStore } from 'pinia'
import { apiFetch } from '../services/api'
import type { ChatMessage } from '../components/dashboard/v2/types'
import type { MissionControlContext } from '../types/mission-control'
import { useOpenClawStore } from './openclaw'
import { createMutationRequestContext } from '../services/mutationContext'
import type { DomainEventDto, OperationResultDto } from '../api/contracts'

let domainEventListener: ((event: Event) => void) | null = null
let eventRefreshTimer: number | null = null

/* ── API Response Shapes ──────────────────────────── */

interface MessageEntry {
  role: string
  content: string
  timestamp: string
}

interface AgentChatResponse {
  runtime: string
  agentId: string
  conversationId: string
  content: string
  runId?: string | null
  state?: string
  operation?: OperationResultDto | null
}

export const useChatStore = defineStore('chat', {
  state: () => ({
    messages: [] as ChatMessage[],
    isThinking: false,
    error: null as string | null,
    refreshInterval: null as ReturnType<typeof setInterval> | null,
    /** Tracks last process timestamp to avoid duplicates */
    lastProcessedTs: 0,
    conversationId: localStorage.getItem('nexus-iris-conversation-id') ?? `nexus-${crypto.randomUUID()}`,
  }),

  getters: {
    messageList: (state) => state.messages,
  },

  actions: {
    /* ── API: Fetch history ─────────────────────── */
    async fetchHistory() {
      try {
        const res = await apiFetch('/api/dashboard/chat/messages?limit=50')
        if (!res.ok) return
        const data: MessageEntry[] = await res.json()

        // Merge new messages (avoid duplicates)
        let mostRecentTs = this.lastProcessedTs
        for (const msg of data) {
          const msgTs = new Date(msg.timestamp).getTime()
          if (msgTs <= this.lastProcessedTs) continue
          if (msgTs > mostRecentTs) mostRecentTs = msgTs

          const sender = msg.role === 'assistant' ? 'iris' as const : 'user' as const
          const tsFormatted = new Date(msg.timestamp).toLocaleTimeString('de-DE', {
            hour: '2-digit',
            minute: '2-digit',
          })

          // Avoid appending duplicates already present
          const exists = this.messages.some(
            m => m.sender === sender && m.text === msg.content && m.ts === tsFormatted
          )
          if (exists) continue

          this.messages.push({
            sender,
            text: msg.content,
            ts: tsFormatted,
          })
        }

        if (mostRecentTs > this.lastProcessedTs) {
          this.lastProcessedTs = mostRecentTs
        }
      } catch (err) {
        console.warn('[ChatStore] fetchHistory failed', err)
      }
    },

    /* ── API: Send message ──────────────────────── */
    async sendMessage(text: string, context?: MissionControlContext) {
      if (!text.trim()) return

      const tsFormatted = new Date().toLocaleTimeString('de-DE', {
        hour: '2-digit',
        minute: '2-digit',
      })

      // Optimistic add: user message
      this.messages.push({
        sender: 'user',
        text: text.trim(),
        ts: tsFormatted,
      })

      this.isThinking = true
      this.error = null

      try {
        const requestContext = createMutationRequestContext('iris-chat')
        const res = await apiFetch('/api/v1/chat', {
          method: 'POST',
          headers: requestContext.headers,
          body: JSON.stringify({
            message: text.trim(),
            conversationId: this.conversationId,
            agentId: 'iris',
            context: context ?? null,
          }),
        })
        const data = await res.json().catch(() => null) as AgentChatResponse | { detail?: string } | null
        if (!res.ok || !data || !('content' in data)) {
          throw new Error(data && 'detail' in data && data.detail
            ? data.detail
            : `OpenClaw chat returned HTTP ${res.status}`)
        }
        this.conversationId = data.conversationId
        localStorage.setItem('nexus-iris-conversation-id', data.conversationId)
        this.messages.push({
          sender: 'iris',
          text: data.content,
          ts: new Date().toLocaleTimeString('de-DE', {
            hour: '2-digit',
            minute: '2-digit',
          }),
          runId: data.runId ?? null,
          runState: data.state ?? null,
          operation: data.operation ?? null,
        })
      } catch (err) {
        console.warn('[ChatStore] sendMessage failed', err)
        this.error = err instanceof Error ? err.message : 'OpenClaw chat is unavailable.'
        this.messages.push({
          sender: 'iris',
          text: this.error,
          ts: new Date().toLocaleTimeString('de-DE', {
            hour: '2-digit',
            minute: '2-digit',
          }),
        })
      } finally {
        this.isThinking = false
      }
    },

    /* ── Polling ─────────────────────────────────── */
    startPolling() {
      if (this.refreshInterval) return
      this.fetchHistory()
      if (!domainEventListener) {
        domainEventListener = (rawEvent: Event) => {
          const detail = (rawEvent as CustomEvent<DomainEventDto>).detail
          if (!detail) return
          if (detail.entity?.type === 'agent-proposal') {
            const operationId = `domain-event:${detail.sequence}`
            if (this.messages.some(message =>
              message.operation?.operationId === operationId
            )) return
            const payload = detail.payload && typeof detail.payload === 'object'
              ? detail.payload as { state?: unknown }
              : null
            const status = typeof payload?.state === 'string'
              ? payload.state
              : 'updated'
            this.messages.push({
              sender: 'iris',
              text: status === 'awaiting_approval'
                ? 'Iris hat einen Agent-Vorschlag zur Owner-Freigabe angelegt.'
                : 'Ein Agent-Vorschlag wurde aktualisiert.',
              ts: new Date(detail.occurredAt).toLocaleTimeString('de-DE', {
                hour: '2-digit',
                minute: '2-digit',
              }),
              operation: {
                operationId,
                status,
                revision: detail.entityRevision,
                primaryRef: detail.entity,
                affectedRefs: [detail.entity],
                traceId: null,
              },
            })
            return
          }
          if (detail.entity?.type !== 'run') return
          if (eventRefreshTimer !== null) window.clearTimeout(eventRefreshTimer)
          eventRefreshTimer = window.setTimeout(() => {
            eventRefreshTimer = null
            void this.fetchHistory()
          }, 400)
        }
        window.addEventListener('nexus:domain-event', domainEventListener)
      }
      this.refreshInterval = setInterval(() => {
        if (useOpenClawStore().syncMode !== 'live') this.fetchHistory()
      }, 60_000)
    },

    stopPolling() {
      if (this.refreshInterval) {
        clearInterval(this.refreshInterval)
        this.refreshInterval = null
      }
      if (domainEventListener) {
        window.removeEventListener('nexus:domain-event', domainEventListener)
        domainEventListener = null
      }
      if (eventRefreshTimer !== null) {
        window.clearTimeout(eventRefreshTimer)
        eventRefreshTimer = null
      }
    },
  },
})
