import { useCallback, useEffect, useState } from "react"
import type { ChatAttachment, DesktopApi, ProjectIntentSuggestion } from "@qjclaw/shared-types"
import type { SubmitPromptOptions } from "./useChatStreamingController"
import { resolvePreferredSessionId } from "../../lib/chat-utils"
import { HOME_CHAT_PROJECT_ID } from "../../lib/constants"

type ViewMode = "chat" | "experts" | "plugins" | "settings" | "knowledge"

export interface PendingHomeIntentSuggestion {
  suggestion: ProjectIntentSuggestion
  prompt: string
  skillId?: string
  attachments?: ChatAttachment[]
}

interface UseHomeIntentSuggestionDeps {
  desktopApi: DesktopApi
  viewMode: ViewMode
  sessionScopeProjectId?: string
  prompt: string
  selectedSkillId: string
  defaultSkillId: string
  composerAttachments: ChatAttachment[]
  setViewMode: (viewMode: ViewMode) => void
  setPrompt: (prompt: string) => void
  setActiveProjectSession: (sessionId: string) => void
  upsertSession: (session: { id: string; projectId: string; title: string; updatedAt: string }) => void
  setSkillMenuOpen: (open: boolean) => void
  setErrorText: (value: string) => void
  submitPrompt: (options: SubmitPromptOptions) => Promise<void>
  switchExpert: (projectId: string) => Promise<void>
  normalizeError: (error: unknown) => string
}

export function useHomeIntentSuggestion(deps: UseHomeIntentSuggestionDeps) {
  const {
    desktopApi,
    viewMode,
    sessionScopeProjectId,
    prompt,
    selectedSkillId,
    defaultSkillId,
    composerAttachments,
    setViewMode,
    setPrompt,
    setActiveProjectSession,
    upsertSession,
    setSkillMenuOpen,
    setErrorText,
    submitPrompt,
    switchExpert,
    normalizeError
  } = deps

  const [pendingHomeIntentSuggestion, setPendingHomeIntentSuggestion] = useState<PendingHomeIntentSuggestion | null>(null)
  const [homeIntentDecisionPending, setHomeIntentDecisionPending] = useState(false)

  useEffect(() => {
    if (viewMode !== "chat") {
      setPendingHomeIntentSuggestion(null)
      setHomeIntentDecisionPending(false)
    }
  }, [viewMode])

  useEffect(() => {
    if (sessionScopeProjectId !== HOME_CHAT_PROJECT_ID) {
      setPendingHomeIntentSuggestion(null)
      setHomeIntentDecisionPending(false)
    }
  }, [sessionScopeProjectId])

  const requestHomeIntentSuggestion = useCallback(async ({
    promptText,
    skillId,
    attachments,
    requireKnownProject = false,
    knownProjectIds
  }: {
    promptText: string
    skillId?: string
    attachments?: ChatAttachment[]
    requireKnownProject?: boolean
    knownProjectIds?: ReadonlySet<string>
  }): Promise<ProjectIntentSuggestion | null> => {
    const trimmedPrompt = promptText.trim()
    if (!trimmedPrompt) {
      setPendingHomeIntentSuggestion(null)
      return null
    }

    const suggestion = await desktopApi.projects.resolveIntent(trimmedPrompt, HOME_CHAT_PROJECT_ID)
    if (!suggestion || (requireKnownProject && knownProjectIds && !knownProjectIds.has(suggestion.projectId))) {
      setPendingHomeIntentSuggestion(null)
      return null
    }

    setPendingHomeIntentSuggestion({
      suggestion,
      prompt: trimmedPrompt,
      skillId,
      attachments
    })
    setSkillMenuOpen(false)
    setErrorText("")
    return suggestion
  }, [desktopApi.projects, setErrorText, setSkillMenuOpen])

  const resolveHomeIntentSuggestion = useCallback(async (nextPrompt?: string) => {
    const currentPrompt = (nextPrompt ?? prompt).trim()
    if (!currentPrompt) {
      setPendingHomeIntentSuggestion(null)
      return { visible: false }
    }
    if (typeof nextPrompt === "string") {
      setPrompt(currentPrompt)
    }

    const skillId = selectedSkillId === defaultSkillId ? undefined : selectedSkillId
    const suggestion = await requestHomeIntentSuggestion({
      promptText: currentPrompt,
      skillId,
      attachments: composerAttachments.length ? composerAttachments : undefined
    })

    if (!suggestion) {
      return { visible: false }
    }

    return {
      visible: true,
      projectId: suggestion.projectId,
      projectName: suggestion.projectName,
      pendingPrompt: currentPrompt
    }
  }, [composerAttachments, defaultSkillId, prompt, requestHomeIntentSuggestion, selectedSkillId, setPrompt])

  const continuePendingHomePromptInHome = useCallback(async (options?: { createSmokeSession?: boolean }) => {
    if (!pendingHomeIntentSuggestion || homeIntentDecisionPending) {
      return { continued: false }
    }

    const pendingRequest = pendingHomeIntentSuggestion
    setHomeIntentDecisionPending(true)
    setPendingHomeIntentSuggestion(null)
    try {
      const homeSession = options?.createSmokeSession
        ? await desktopApi.chat.createSessionForProject(HOME_CHAT_PROJECT_ID, "Smoke Home Intent")
        : undefined
      const forcedSessionId = homeSession?.id
      if (homeSession) {
        upsertSession(homeSession)
        setViewMode("chat")
        setActiveProjectSession(homeSession.id)
      }

      await submitPrompt({
        promptText: pendingRequest.prompt,
        skillId: pendingRequest.skillId,
        forcedSessionId,
        forcedProjectId: HOME_CHAT_PROJECT_ID,
        forcedAttachments: pendingRequest.attachments
      })

      return {
        continued: true,
        sessionId: forcedSessionId
      }
    } finally {
      setHomeIntentDecisionPending(false)
    }
  }, [desktopApi.chat, homeIntentDecisionPending, pendingHomeIntentSuggestion, setActiveProjectSession, setViewMode, submitPrompt, upsertSession])

  const switchExpertAndContinuePendingHomePrompt = useCallback(async (options?: { smokeTitle?: string; throwOnError?: boolean }) => {
    if (!pendingHomeIntentSuggestion || homeIntentDecisionPending) {
      return {
        switched: false,
        projectId: undefined
      }
    }

    const pendingRequest = pendingHomeIntentSuggestion
    setHomeIntentDecisionPending(true)
    setPendingHomeIntentSuggestion(null)
    setErrorText("")

    try {
      setViewMode("experts")
      await switchExpert(pendingRequest.suggestion.projectId)

      const projectSessions = await desktopApi.chat.listSessionsByProject(pendingRequest.suggestion.projectId)
      const ensuredSessionId = resolvePreferredSessionId(projectSessions)
        ?? (await desktopApi.chat.createSessionForProject(pendingRequest.suggestion.projectId, options?.smokeTitle)).id
      setActiveProjectSession(ensuredSessionId)

      await submitPrompt({
        promptText: pendingRequest.prompt,
        skillId: pendingRequest.skillId,
        forcedSessionId: ensuredSessionId,
        forcedProjectId: pendingRequest.suggestion.projectId,
        forcedAttachments: pendingRequest.attachments
      })

      return {
        switched: true,
        projectId: pendingRequest.suggestion.projectId,
        sessionId: ensuredSessionId
      }
    } catch (error) {
      setViewMode("chat")
      setPendingHomeIntentSuggestion(pendingRequest)
      setErrorText(normalizeError(error))
      if (options?.throwOnError) {
        throw error
      }
      return {
        switched: false,
        projectId: pendingRequest.suggestion.projectId
      }
    } finally {
      setHomeIntentDecisionPending(false)
    }
  }, [desktopApi.chat, homeIntentDecisionPending, normalizeError, pendingHomeIntentSuggestion, setActiveProjectSession, setErrorText, setViewMode, submitPrompt, switchExpert])

  const dismissPendingHomeIntentSuggestion = useCallback(() => {
    if (homeIntentDecisionPending) {
      return
    }
    setPendingHomeIntentSuggestion(null)
  }, [homeIntentDecisionPending])

  return {
    pendingHomeIntentSuggestion,
    homeIntentDecisionPending,
    requestHomeIntentSuggestion,
    resolveHomeIntentSuggestion,
    continuePendingHomePromptInHome,
    switchExpertAndContinuePendingHomePrompt,
    dismissPendingHomeIntentSuggestion
  }
}
