import { useCallback, useEffect, useState } from 'react'
import { useLocation, useNavigate } from 'react-router-dom'
import { api, streamIslanderChat } from '../../api/client'
import {
  buildIslanderContext,
  capturePageSnapshot,
  formatPageSnapshot,
  runIslanderAgentTurn,
  userWantsPageContext,
  useIslanderPageContext,
} from '../../lib/islander'
import {
  clampIslanderPosition,
  ISLANDER_DOCK_HEIGHT,
  ISLANDER_DOCK_WIDTH,
  ISLANDER_DRAG_THRESHOLD,
  ISLANDER_EXPANDED_KEY,
  readIslanderExpandedPreference,
  useIslanderPosition,
} from '../../lib/islander/useIslanderPosition'
import { useOnboarding } from '../../onboarding/OnboardingContext'
import { useThreadsAccount } from '../../threads/ThreadsAccountContext'
import type { ThreadsAccountAiSettingsData } from '../../types/api'
import type { IslanderChatTurn } from '../../lib/islander/types'
import { IslanderAvatar } from './IslanderAvatar'
import { IslanderChatPanel, type IslanderChatMessage } from './IslanderChatPanel'

function nextMessageId() {
  return `msg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
}

export function IslanderCompanion() {
  const { pathname } = useLocation()
  const navigate = useNavigate()
  const pageCtx = useIslanderPageContext()
  const { activeAccount, activeAccountId } = useThreadsAccount()
  const onboarding = useOnboarding()
  const { position, dragging, setDragging, dragRef, updatePosition } = useIslanderPosition()

  const [expanded, setExpanded] = useState(readIslanderExpandedPreference)
  const [messages, setMessages] = useState<IslanderChatMessage[]>([])
  const [input, setInput] = useState('')
  const [streaming, setStreaming] = useState(false)
  const [acting, setActing] = useState(false)
  const [error, setError] = useState('')
  const [aiReady, setAiReady] = useState(false)

  const pageMeta = pageCtx?.runtimeMeta ?? null

  const setExpandedPersisted = useCallback((value: boolean | ((prev: boolean) => boolean)) => {
    setExpanded((prev) => {
      const next = typeof value === 'function' ? value(prev) : value
      try {
        localStorage.setItem(ISLANDER_EXPANDED_KEY, next ? '1' : '0')
      } catch {
        // ignore
      }
      return next
    })
  }, [])

  useEffect(() => {
    if (!activeAccountId) {
      setAiReady(false)
      return
    }
    api
      .get<ThreadsAccountAiSettingsData>(
        `/api/v1/threads-accounts/${encodeURIComponent(activeAccountId)}/ai-settings`,
        { auth: true },
      )
      .then((data) => {
        const provider = data.provider
        const primary = data.api_keys_configured?.[provider]
        const anyConfigured = Object.values(data.api_keys_configured ?? {}).some(
          (value) => value === true || value === 'true',
        )
        setAiReady(primary === true || primary === 'true' || anyConfigured)
      })
      .catch(() => setAiReady(false))
  }, [activeAccountId])

  const sendMessage = useCallback(
    async (text: string) => {
      const trimmed = text.trim()
      if (!trimmed || streaming || acting || !aiReady) return

      setError('')
      setStreaming(true)
      setActing(false)

      const userMessage: IslanderChatMessage = {
        id: nextMessageId(),
        role: 'user',
        content: trimmed,
      }
      const assistantId = nextMessageId()
      const history: IslanderChatTurn[] = [
        ...messages
          .filter((item): item is IslanderChatMessage & { role: 'user' | 'assistant' } =>
            item.role === 'user' || item.role === 'assistant',
          )
          .map((item) => ({
            role: item.role,
            content: item.content,
          })),
        { role: 'user', content: trimmed },
      ]

      setMessages((prev) => [...prev, userMessage, { id: assistantId, role: 'assistant', content: '' }])
      setInput('')

      const includePageDetail = userWantsPageContext(trimmed)
      const turnSnapshot = includePageDetail ? capturePageSnapshot() : undefined

      try {
        await runIslanderAgentTurn({
          history,
          assistantId,
          buildContext: ({ includePageDetail: withPage }) =>
            buildIslanderContext({
              pathname,
              activeAccount,
              onboarding,
              pageSnapshot:
                withPage && turnSnapshot
                  ? formatPageSnapshot(turnSnapshot)
                  : withPage
                    ? formatPageSnapshot(capturePageSnapshot())
                    : undefined,
              pageMeta,
              includePageDetail: withPage,
            }),
          initialIncludePageDetail: includePageDetail,
          pageSnapshot: turnSnapshot,
          navigate,
          streamChat: async (payload, context, onDelta) => {
            await new Promise<void>((resolve, reject) => {
              void streamIslanderChat(
                { messages: payload, context },
                (delta) => onDelta(delta),
                () => resolve(),
                (message) => reject(new Error(message)),
              )
            })
          },
          callbacks: {
            onAssistantDelta: (id, visibleContent) => {
              setMessages((prev) =>
                prev.map((item) => (item.id === id ? { ...item, content: visibleContent } : item)),
              )
            },
            onAssistantStart: () => {
              const id = nextMessageId()
              setMessages((prev) => [...prev, { id, role: 'assistant', content: '' }])
              return id
            },
            onSystemMessage: (content) => {
              const id = nextMessageId()
              setMessages((prev) => [...prev, { id, role: 'system', content }])
              return id
            },
            onSystemMessageUpdate: (id, content) => {
              setMessages((prev) =>
                prev.map((item) => (item.id === id ? { ...item, content } : item)),
              )
            },
            onActingChange: setActing,
          },
        })
      } catch (message) {
        setError(message instanceof Error ? message.message : '聊天失敗')
      } finally {
        setStreaming(false)
        setActing(false)
      }
    },
    [acting, aiReady, activeAccount, messages, navigate, onboarding, pageMeta, pathname, streaming],
  )

  const beginDrag = (event: React.PointerEvent<HTMLButtonElement>) => {
    event.preventDefault()
    event.currentTarget.setPointerCapture(event.pointerId)
    dragRef.current = {
      active: true,
      moved: false,
      pointerId: event.pointerId,
      startX: event.clientX,
      startY: event.clientY,
      originX: position.x,
      originY: position.y,
    }
  }

  const moveDrag = (event: React.PointerEvent<HTMLButtonElement>) => {
    const drag = dragRef.current
    if (!drag.active || drag.pointerId !== event.pointerId) return

    const dx = event.clientX - drag.startX
    const dy = event.clientY - drag.startY
    if (!drag.moved && (Math.abs(dx) > ISLANDER_DRAG_THRESHOLD || Math.abs(dy) > ISLANDER_DRAG_THRESHOLD)) {
      drag.moved = true
      setDragging(true)
    }
    if (!drag.moved) return

    updatePosition(
      clampIslanderPosition(
        { x: drag.originX + dx, y: drag.originY + dy },
        { width: ISLANDER_DOCK_WIDTH, height: ISLANDER_DOCK_HEIGHT },
      ),
    )
  }

  const endDrag = (event: React.PointerEvent<HTMLButtonElement>) => {
    const drag = dragRef.current
    if (!drag.active || drag.pointerId !== event.pointerId) return

    drag.active = false
    setDragging(false)

    if (drag.moved) {
      updatePosition(position)
      return
    }

    setExpandedPersisted((value) => !value)
  }

  const openUpward = position.y > window.innerHeight * 0.42
  const busy = streaming || acting

  return (
    <div
      className={`ac-islander ${dragging ? 'ac-islander--dragging' : ''}`}
      style={{
        left: position.x,
        top: position.y,
        width: ISLANDER_DOCK_WIDTH,
        height: ISLANDER_DOCK_HEIGHT,
      }}
      aria-label="島民嚮導"
    >
      <div className="ac-islander__anchor">
        <button
          type="button"
          onPointerDown={beginDrag}
          onPointerMove={moveDrag}
          onPointerUp={endDrag}
          onPointerCancel={endDrag}
          className={`ac-islander__dock ${busy ? 'ac-islander__dock--thinking' : ''}`}
          aria-expanded={expanded}
          aria-label={expanded ? '收合島民聊天' : '展開島民聊天'}
        >
          <IslanderAvatar thinking={busy} />
          {!aiReady ? <span className="ac-islander__dock-dot" aria-hidden /> : null}
        </button>

        {expanded ? (
          <div
            className={`ac-islander__panel-wrap ${
              openUpward ? 'ac-islander__panel-wrap--above' : 'ac-islander__panel-wrap--below'
            }`}
          >
            <IslanderChatPanel
              messages={messages}
              input={input}
              streaming={streaming}
              acting={acting}
              error={error}
              aiReady={aiReady}
              suggestions={[]}
              onInputChange={setInput}
              onSend={() => sendMessage(input)}
              onSuggestion={(text) => {
                setInput(text)
                sendMessage(text).catch(() => undefined)
              }}
              onClose={() => setExpandedPersisted(false)}
            />
          </div>
        ) : null}
      </div>
    </div>
  )
}