import { For, Show, createSignal, createEffect, createMemo } from "solid-js"
import type { Message } from "../types/message"
import MessageItem from "./message-item"
import ToolCall from "./tool-call"
import { sseManager } from "../lib/sse-manager"
import Kbd from "./kbd"
import { preferences } from "../stores/preferences"
import { providers, getSessionInfo } from "../stores/sessions"

// Calculate session tokens and cost from messagesInfo (matches TUI logic)
function calculateSessionInfo(messagesInfo?: Map<string, any>, instanceId?: string) {
  if (!messagesInfo || messagesInfo.size === 0)
    return { tokens: 0, cost: 0, contextWindow: 0, isSubscriptionModel: false }

  let tokens = 0
  let cost = 0
  let contextWindow = 0
  let isSubscriptionModel = false
  let modelID = ""
  let providerID = ""

  // Go backwards through messages to find the last relevant assistant message (like TUI)
  const messageArray = Array.from(messagesInfo.values()).reverse()

  for (const info of messageArray) {
    if (info.role === "assistant" && info.tokens) {
      const usage = info.tokens

      if (usage.output > 0) {
        if (info.summary) {
          // If summary message, only count output tokens and stop (like TUI)
          tokens = usage.output || 0
          cost = info.cost || 0
        } else {
          // Regular message - count all token types (like TUI)
          tokens =
            (usage.input || 0) +
            (usage.cache?.read || 0) +
            (usage.cache?.write || 0) +
            (usage.output || 0) +
            (usage.reasoning || 0)
          cost = info.cost || 0
        }

        // Get model info for context window and subscription check
        modelID = info.modelID || ""
        providerID = info.providerID || ""
        isSubscriptionModel = cost === 0

        break
      }
    }
  }

  // Try to get context window from providers
  if (instanceId && modelID && providerID) {
    const instanceProviders = providers().get(instanceId) || []
    console.log("[calculateSessionInfo] instanceProviders:", instanceProviders)
    console.log("[calculateSessionInfo] looking for providerID:", providerID, "modelID:", modelID)
    const provider = instanceProviders.find((p) => p.id === providerID)
    console.log("[calculateSessionInfo] found provider:", provider)
    if (provider) {
      const model = provider.models.find((m) => m.id === modelID)
      console.log("[calculateSessionInfo] found model:", model)
      if (model?.limit?.context) {
        contextWindow = model.limit.context
      }
      // Check if it's a subscription model (cost is 0 for both input and output)
      if (model?.cost?.input === 0 && model?.cost?.output === 0) {
        isSubscriptionModel = true
      }
    }
  }

  return { tokens, cost, contextWindow, isSubscriptionModel }
}

// Format tokens like TUI (e.g., "110K", "1.2M")
function formatTokens(tokens: number): string {
  if (tokens >= 1000000) {
    return `${(tokens / 1000000).toFixed(1)}M`
  } else if (tokens >= 1000) {
    return `${(tokens / 1000).toFixed(0)}K`
  }
  return tokens.toString()
}

// Format session info like TUI (e.g., "110K/73% ($0.42)" or "110K/73%")
function formatSessionInfo(tokens: number, cost: number, contextWindow: number, isSubscriptionModel: boolean): string {
  const tokensStr = formatTokens(tokens)

  // Calculate percentage if we have context window
  if (contextWindow > 0) {
    const percentage = Math.round((tokens / contextWindow) * 100)
    if (isSubscriptionModel) {
      return `${tokensStr}/${percentage}%`
    }
    return `${tokensStr}/${percentage}% ($${cost.toFixed(2)})`
  }

  // Fallback without context window
  if (isSubscriptionModel) {
    return tokensStr
  }
  return `${tokensStr} ($${cost.toFixed(2)})`
}

interface MessageStreamProps {
  instanceId: string
  sessionId: string
  messages: Message[]
  messagesInfo?: Map<string, any>
  revert?: {
    messageID: string
    partID?: string
    snapshot?: string
    diff?: string
  }
  loading?: boolean
  onRevert?: (messageId: string) => void
}

interface DisplayItem {
  type: "message" | "tool"
  data: any
  messageInfo?: any
}

export default function MessageStream(props: MessageStreamProps) {
  let containerRef: HTMLDivElement | undefined
  const [autoScroll, setAutoScroll] = createSignal(true)
  const [showScrollButton, setShowScrollButton] = createSignal(false)

  const connectionStatus = () => sseManager.getStatus(props.instanceId)

  const sessionInfo = createMemo(() => {
    return (
      getSessionInfo(props.instanceId, props.sessionId) || {
        tokens: 0,
        cost: 0,
        contextWindow: 0,
        isSubscriptionModel: false,
      }
    )
  })

  const formattedSessionInfo = createMemo(() => {
    const sessionInfo = getSessionInfo(props.instanceId, props.sessionId) || {
      tokens: 0,
      cost: 0,
      contextWindow: 0,
      isSubscriptionModel: false,
    }
    return formatSessionInfo(
      sessionInfo.tokens,
      sessionInfo.cost,
      sessionInfo.contextWindow,
      sessionInfo.isSubscriptionModel,
    )
  })

  function scrollToBottom() {
    if (containerRef) {
      containerRef.scrollTop = containerRef.scrollHeight
      setAutoScroll(true)
      setShowScrollButton(false)
    }
  }

  function handleScroll() {
    if (!containerRef) return

    const { scrollTop, scrollHeight, clientHeight } = containerRef
    const isAtBottom = scrollHeight - scrollTop - clientHeight < 50

    setAutoScroll(isAtBottom)
    setShowScrollButton(!isAtBottom)
  }

  const displayItems = createMemo(() => {
    const items: DisplayItem[] = []

    let lastAssistantMessageId = ""
    for (let i = props.messages.length - 1; i >= 0; i--) {
      if (props.messages[i].type === "assistant") {
        lastAssistantMessageId = props.messages[i].id
        break
      }
    }

    for (const message of props.messages) {
      const messageInfo = props.messagesInfo?.get(message.id)

      // If we hit the revert point, stop rendering messages
      if (props.revert?.messageID && message.id === props.revert.messageID) {
        break
      }

      const textParts = message.parts.filter((p) => p.type === "text" && !p.synthetic)
      const toolParts = message.parts.filter((p) => p.type === "tool")
      const reasoningParts = preferences().showThinkingBlocks ? message.parts.filter((p) => p.type === "reasoning") : []

      const isQueued = message.type === "user" && message.id > lastAssistantMessageId

      if (textParts.length > 0 || reasoningParts.length > 0 || messageInfo?.error) {
        items.push({
          type: "message",
          data: {
            ...message,
            parts: [...textParts, ...reasoningParts],
            isQueued,
          },
          messageInfo,
        })
      }

      for (const toolPart of toolParts) {
        items.push({
          type: "tool",
          data: toolPart,
          messageInfo,
        })
      }
    }

    return items
  })

  const itemsLength = () => displayItems().length
  createEffect(() => {
    itemsLength()
    if (autoScroll()) {
      setTimeout(scrollToBottom, 0)
    }
  })

  return (
    <div class="message-stream-container">
      <div class="connection-status">
        <div class="flex items-center gap-2 text-sm font-medium text-gray-700">
          <span>{formattedSessionInfo()}</span>
        </div>
        <div class="flex-1" />
        <div class="flex items-center gap-2 text-sm font-medium text-gray-700">
          <span>Command Palette</span>
          <Kbd shortcut="cmd+shift+p" />
        </div>
        <div class="flex-1 flex items-center justify-end gap-3">
          <Show when={connectionStatus() === "connected"}>
            <span class="status-indicator connected">
              <span class="status-dot" />
              Connected
            </span>
          </Show>
          <Show when={connectionStatus() === "connecting"}>
            <span class="status-indicator connecting">
              <span class="status-dot" />
              Connecting...
            </span>
          </Show>
          <Show when={connectionStatus() === "error" || connectionStatus() === "disconnected"}>
            <span class="status-indicator disconnected">
              <span class="status-dot" />
              Disconnected
            </span>
          </Show>
        </div>
      </div>
      <div ref={containerRef} class="message-stream" onScroll={handleScroll}>
        <Show when={!props.loading && displayItems().length === 0}>
          <div class="empty-state">
            <div class="empty-state-content">
              <h3>Start a conversation</h3>
              <p>Type a message below or try:</p>
              <ul>
                <li>
                  <code>/init-project</code>
                </li>
                <li>Ask about your codebase</li>
                <li>
                  Attach files with <code>@</code>
                </li>
              </ul>
            </div>
          </div>
        </Show>

        <Show when={props.loading}>
          <div class="loading-state">
            <div class="spinner" />
            <p>Loading messages...</p>
          </div>
        </Show>

        <For each={displayItems()} fallback={null}>
          {(item, index) => {
            const key = item.type === "message" ? `msg-${item.data.id}` : `tool-${item.data.id}`
            return (
              <Show
                when={item.type === "message"}
                fallback={
                  <div class="tool-call-message" data-key={key}>
                    <div class="tool-call-header-label">
                      <span class="tool-call-icon">🔧</span>
                      <span>Tool Call</span>
                      <span class="tool-name">{item.data?.tool || "unknown"}</span>
                    </div>
                    <ToolCall toolCall={item.data} toolCallId={item.data.id} />
                  </div>
                }
              >
                <MessageItem
                  message={item.data}
                  messageInfo={item.messageInfo}
                  isQueued={item.data.isQueued}
                  onRevert={props.onRevert}
                />
              </Show>
            )
          }}
        </For>
      </div>

      <Show when={showScrollButton()}>
        <button class="scroll-to-bottom" onClick={scrollToBottom} aria-label="Scroll to bottom">
          ↓
        </button>
      </Show>
    </div>
  )
}
