// SPDX-FileCopyrightText: 2025 Weibo, Inc.
//
// SPDX-License-Identifier: Apache-2.0

'use client'

import React from 'react'
import { CircleStop } from 'lucide-react'
import ModelSelector, { Model } from '../selector/ModelSelector'
import TeamSelectorButton from '../selector/TeamSelectorButton'
import UnifiedRepositorySelector from '../selector/UnifiedRepositorySelector'
import ClarificationToggle from '../clarification/ClarificationToggle'
import CorrectionModeToggle from '../CorrectionModeToggle'
import ChatContextInput from '../chat/ChatContextInput'
import AttachmentButton from '../AttachmentButton'
import SendButton from './SendButton'
import LoadingDots from '../message/LoadingDots'
import QuotaUsage from '../params/QuotaUsage'
import { ActionButton } from '@/components/ui/action-button'
import type {
  Team,
  GitRepoInfo,
  GitBranch,
  TaskDetail,
  MultiAttachmentUploadState,
  TaskType,
} from '@/types/api'
import type { ContextItem } from '@/types/context'
import type { UnifiedSkill } from '@/apis/skills'
import { canUseChatContexts, isChatShell } from '../../service/messageService'
import { supportsAttachments } from '../../service/attachmentService'
import { useIsMobile } from '@/features/layout/hooks/useMediaQuery'
import { MobileChatInputControls } from './MobileChatInputControls'
import SkillSelectorPopover, { SkillSelectorPopoverRef } from '../selector/SkillSelectorPopover'
import {
  ImageSizeSelector,
  GenerateModeSelector,
  isGenerateMode,
  VideoSettingsPopover,
} from '../selector'
import type { GenerateMode } from '../selector'
import { ProjectSelectorTab } from '@/features/projects/components/ProjectSelectorTab'
import { getChatSendState } from './chatSendState'

export interface ChatInputControlsProps {
  /** Task type to determine which controls to show */
  taskType?: TaskType
  // Team and Model
  selectedTeam: Team | null
  /** Available teams for team selector */
  teams?: Team[]
  onTeamChange?: (team: Team) => void
  /** Callback to refresh teams list after creation */
  onTeamsRefresh?: () => Promise<void>
  selectedModel: Model | null
  setSelectedModel: (model: Model | null) => void
  forceOverride: boolean
  setForceOverride: (value: boolean) => void
  /** Current team ID for model preference storage */
  teamId?: number | null
  /** Current task ID for session-level model preference storage (null for new chat) */
  taskId?: number | null
  /** Task's model_id from backend - used as fallback when no session preference exists */
  taskModelId?: string | null
  /** Knowledge base ID to exclude from context selector (used in notebook mode) */
  knowledgeBaseId?: number

  // Repository and Branch
  showRepositorySelector: boolean
  selectedRepo: GitRepoInfo | null
  setSelectedRepo: (repo: GitRepoInfo | null) => void
  selectedBranch: GitBranch | null
  setSelectedBranch: (branch: GitBranch | null) => void
  selectedTaskDetail: TaskDetail | null
  /** Effective requires workspace value (considering user override) */
  effectiveRequiresWorkspace?: boolean
  /** Callback when user toggles the requires workspace switch */
  onRequiresWorkspaceChange?: (value: boolean) => void

  // Deep Thinking and Clarification
  enableDeepThinking: boolean
  setEnableDeepThinking: (value: boolean) => void
  enableClarification: boolean
  setEnableClarification: (value: boolean) => void

  // Correction mode
  enableCorrectionMode?: boolean
  correctionModelName?: string | null
  onCorrectionModeToggle?: (enabled: boolean, modelId?: string, modelName?: string) => void

  // Context selection (knowledge bases)
  selectedContexts: ContextItem[]
  setSelectedContexts: (contexts: ContextItem[]) => void

  // Attachment (multi-attachment)
  attachmentState: MultiAttachmentUploadState
  onFileSelect: (files: File | File[]) => void
  onAttachmentRemove: (attachmentId: number) => void

  // State flags
  isLoading: boolean
  isStreaming: boolean
  isAwaitingResponseStart?: boolean
  isStopping: boolean
  hasMessages: boolean
  shouldCollapseSelectors: boolean
  shouldHideQuotaUsage: boolean
  shouldHideChatInput: boolean
  isModelSelectionRequired: boolean
  isAttachmentReadyToSend: boolean
  taskInputMessage: string
  isSubtaskStreaming: boolean
  canQueueMessage?: boolean
  canSendGuidance?: boolean

  // Actions
  onStopStream: () => void
  onCancelTask?: () => void
  isCancelling?: boolean
  onSendMessage: () => void
  onSendGuidance?: () => void

  // Whether there are no available teams (shows disabled state)
  hasNoTeams?: boolean

  // Skill selector support
  availableSkills?: UnifiedSkill[]
  teamSkillNames?: string[]
  preloadedSkillNames?: string[]
  selectedSkillNames?: string[]
  onToggleSkill?: (skillName: string) => void

  // Ref for skill selector button (for fly animation)
  skillSelectorRef?: React.RefObject<SkillSelectorPopoverRef | null>

  // Video mode props (only used when taskType === 'video')
  videoModels?: Model[]
  selectedVideoModel?: Model | null
  onVideoModelChange?: (model: Model) => void
  isVideoModelsLoading?: boolean
  selectedResolution?: string
  onResolutionChange?: (resolution: string) => void
  availableResolutions?: string[]
  selectedRatio?: string
  onRatioChange?: (ratio: string) => void
  availableRatios?: string[]
  selectedDuration?: number
  onDurationChange?: (duration: number) => void
  availableDurations?: number[]

  // Image mode props (only used when taskType === 'image')
  selectedImageModel?: Model | null
  onImageModelChange?: (model: Model) => void
  isImageModelsLoading?: boolean
  selectedImageSize?: string
  onImageSizeChange?: (size: string) => void

  // Generate mode switch props (only used when taskType is 'video' or 'image')
  /** Callback when user switches between video and image mode */
  onGenerateModeChange?: (mode: GenerateMode) => void

  /** When true, hide all selectors - only show send button + quota */
  hideSelectors?: boolean

  /** Project ID for project selector (workspace projects) */
  projectId?: number | null
}

/**
 * ChatInputControls Component
 *
 * Renders the bottom control bar of the chat input area, including:
 * - File upload button
 * - Clarification toggle
 * - Model selector
 * - Repository selector (for code tasks)
 * - Branch selector (for code tasks)
 * - Quota usage display
 * - Deep thinking toggle
 * - Send/Stop button
 *
 * This component is used in both the empty state (no messages) and
 * the messages state (floating input) of ChatArea.
 */
export function ChatInputControls({
  taskType,
  selectedTeam,
  teams = [],
  onTeamChange,
  onTeamsRefresh,
  selectedModel,
  setSelectedModel,
  forceOverride,
  setForceOverride,
  teamId,
  taskId,
  taskModelId,
  knowledgeBaseId,
  showRepositorySelector,
  selectedRepo,
  setSelectedRepo,
  selectedBranch,
  setSelectedBranch,
  selectedTaskDetail,
  effectiveRequiresWorkspace,
  onRequiresWorkspaceChange,
  enableClarification,
  setEnableClarification,
  enableCorrectionMode = false,
  correctionModelName,
  onCorrectionModeToggle,
  selectedContexts,
  setSelectedContexts,
  attachmentState: _attachmentState,
  onFileSelect,
  onAttachmentRemove: _onAttachmentRemove,
  isLoading,
  isStreaming,
  isAwaitingResponseStart = false,
  isStopping,
  hasMessages,
  shouldCollapseSelectors,
  shouldHideQuotaUsage,
  shouldHideChatInput,
  isModelSelectionRequired,
  isAttachmentReadyToSend,
  taskInputMessage,
  isSubtaskStreaming,
  canQueueMessage = false,
  canSendGuidance = false,
  onStopStream,
  onCancelTask,
  isCancelling = false,
  onSendMessage,
  onSendGuidance,
  hasNoTeams = false,
  availableSkills = [],
  teamSkillNames = [],
  preloadedSkillNames = [],
  selectedSkillNames = [],
  onToggleSkill,
  skillSelectorRef,
  // Video mode props
  videoModels: _videoModels = [],
  selectedVideoModel,
  onVideoModelChange,
  isVideoModelsLoading = false,
  selectedResolution = '720p',
  onResolutionChange,
  availableResolutions,
  selectedRatio = '16:9',
  onRatioChange,
  availableRatios,
  selectedDuration = 5,
  onDurationChange,
  availableDurations,
  // Image mode props
  selectedImageModel,
  onImageModelChange,
  isImageModelsLoading = false,
  selectedImageSize = '1024x1024',
  onImageSizeChange,
  // Generate mode switch props
  onGenerateModeChange,
  // Hide all selectors (for OpenClaw devices)
  hideSelectors,
  // Project context
  projectId,
}: ChatInputControlsProps) {
  // Check if we're in video or image mode
  const isVideoMode = taskType === 'video'
  const isImageMode = taskType === 'image'
  // Check if we're in generation mode (video or image)
  const isGenerationMode = isVideoMode || isImageMode
  // Always use compact mode (icon only) to save space
  const shouldUseCompactQuota = true
  const isMobile = useIsMobile()
  const showChatContexts = canUseChatContexts(taskType, selectedTeam)

  // Determine the send button state
  const renderSendButton = () => {
    const sendState = getChatSendState({
      isLoading,
      isStreaming,
      isAwaitingResponseStart,
      isStopping,
      isModelSelectionRequired,
      isAttachmentReadyToSend,
      hasNoTeams,
      shouldHideChatInput,
      taskInputMessage,
      selectedTaskStatus: selectedTaskDetail?.status,
      isSubtaskStreaming,
      isGroupChat: selectedTaskDetail?.is_group_chat,
      canQueueMessage,
    })

    const renderStopAction = () => (
      <ActionButton
        onClick={onStopStream}
        title="Stop generating"
        icon={<CircleStop className="h-4 w-4 text-orange-500" />}
        className="hover:bg-orange-100"
      />
    )

    const renderStoppingAction = () => (
      <ActionButton
        variant="loading"
        icon={
          <>
            <div className="absolute inset-0 rounded-full border-2 border-orange-200 border-t-orange-500 animate-spin" />
            <CircleStop className="h-4 w-4 text-orange-500" />
          </>
        }
      />
    )

    const renderCancelTaskAction = () => {
      if (isCancelling) {
        return renderStoppingAction()
      }

      return (
        <ActionButton
          onClick={onCancelTask}
          title="Cancel task"
          icon={<CircleStop className="h-4 w-4 text-orange-500" />}
          className="hover:bg-orange-100"
          data-testid="cancel-task-button"
        />
      )
    }

    if (sendState.primaryAction === 'loading') {
      if (sendState.showStopAction) {
        return renderStoppingAction()
      }

      if (sendState.showPendingAction) {
        return <ActionButton disabled variant="loading" icon={<LoadingDots />} />
      }

      return <ActionButton disabled variant="loading" icon={<LoadingDots />} />
    }

    if (sendState.primaryAction === 'stop') {
      return renderStopAction()
    }

    if (sendState.primaryAction === 'cancel') {
      return renderCancelTaskAction()
    }

    if (sendState.primaryAction === 'queue') {
      return (
        <div className="flex items-center gap-2">
          {renderStopAction()}
          <SendButton
            onClick={onSendMessage}
            disabled={sendState.isPrimaryDisabled}
            isLoading={isLoading}
            ariaLabel="Queue message"
          />
        </div>
      )
    }

    return (
      <SendButton
        onClick={onSendMessage}
        disabled={sendState.isPrimaryDisabled}
        isLoading={isLoading}
      />
    )
  }

  // Mobile: delegate to MobileChatInputControls
  if (isMobile) {
    return (
      <MobileChatInputControls
        selectedTeam={selectedTeam}
        teams={teams}
        onTeamChange={onTeamChange}
        taskType={taskType}
        selectedModel={selectedModel}
        setSelectedModel={setSelectedModel}
        forceOverride={forceOverride}
        setForceOverride={setForceOverride}
        teamId={teamId}
        taskId={taskId}
        taskModelId={taskModelId}
        knowledgeBaseId={knowledgeBaseId}
        showRepositorySelector={showRepositorySelector}
        selectedRepo={selectedRepo}
        setSelectedRepo={setSelectedRepo}
        selectedBranch={selectedBranch}
        setSelectedBranch={setSelectedBranch}
        selectedTaskDetail={selectedTaskDetail}
        effectiveRequiresWorkspace={effectiveRequiresWorkspace}
        onRequiresWorkspaceChange={hasMessages ? undefined : onRequiresWorkspaceChange}
        enableClarification={enableClarification}
        setEnableClarification={setEnableClarification}
        enableCorrectionMode={enableCorrectionMode}
        correctionModelName={correctionModelName}
        onCorrectionModeToggle={onCorrectionModeToggle}
        selectedContexts={selectedContexts}
        setSelectedContexts={setSelectedContexts}
        onFileSelect={onFileSelect}
        isLoading={isLoading}
        isStreaming={isStreaming}
        isAwaitingResponseStart={isAwaitingResponseStart}
        isStopping={isStopping}
        hasMessages={hasMessages}
        shouldHideChatInput={shouldHideChatInput}
        isModelSelectionRequired={isModelSelectionRequired}
        isAttachmentReadyToSend={isAttachmentReadyToSend}
        taskInputMessage={taskInputMessage}
        isSubtaskStreaming={isSubtaskStreaming}
        canQueueMessage={canQueueMessage}
        canSendGuidance={canSendGuidance}
        onStopStream={onStopStream}
        onCancelTask={onCancelTask}
        isCancelling={isCancelling}
        onSendMessage={onSendMessage}
        onSendGuidance={onSendGuidance}
        hasNoTeams={hasNoTeams}
        availableSkills={availableSkills}
        teamSkillNames={teamSkillNames}
        preloadedSkillNames={preloadedSkillNames}
        selectedSkillNames={selectedSkillNames}
        onToggleSkill={onToggleSkill}
        hideSelectors={hideSelectors}
      />
    )
  }

  // Desktop layout: original full layout
  return (
    <div
      className={`flex items-center justify-between px-2 ${shouldHideChatInput ? 'py-3' : 'pb-2 -mt-2.5'}`}
    >
      <div
        className="flex-1 min-w-0 overflow-visible flex items-center gap-0 flex-wrap"
        data-tour="input-controls"
        data-testid="input-controls"
      >
        {/* Generate Mode Selector - show when in video or image mode */}
        {isGenerateMode(taskType) && onGenerateModeChange && (
          <GenerateModeSelector
            selectedMode={taskType as GenerateMode}
            onModeChange={onGenerateModeChange}
            disabled={isLoading || isStreaming || hasMessages}
          />
        )}

        {/* Reference image upload button - show for image and video generation modes,
            placed between the mode toggle and the model selector */}
        {isGenerationMode && (
          <AttachmentButton
            onFileSelect={onFileSelect}
            disabled={isLoading || isStreaming}
            accept="image/*"
          />
        )}

        {/* Video Mode Controls - show when taskType is 'video' */}
        {isVideoMode && (
          <>
            {/* Video Model Selector - using unified ModelSelector with video category */}
            {onVideoModelChange && (
              <ModelSelector
                selectedModel={selectedVideoModel ?? null}
                setSelectedModel={model => model && onVideoModelChange(model)}
                forceOverride={false}
                setForceOverride={() => {}}
                selectedTeam={null}
                disabled={isLoading || isStreaming}
                isLoading={isVideoModelsLoading}
                modelCategoryType="video"
              />
            )}

            {/* Unified Video Settings Popover (ratio + duration + resolution) */}
            {onResolutionChange && onRatioChange && onDurationChange && (
              <VideoSettingsPopover
                selectedRatio={selectedRatio}
                onRatioChange={onRatioChange}
                availableRatios={availableRatios ?? ['16:9', '9:16', '1:1']}
                selectedDuration={selectedDuration}
                onDurationChange={onDurationChange}
                availableDurations={availableDurations ?? [5, 10]}
                selectedResolution={selectedResolution}
                onResolutionChange={onResolutionChange}
                availableResolutions={availableResolutions ?? ['480p', '720p', '1080p']}
                disabled={isLoading || isStreaming}
              />
            )}
          </>
        )}

        {/* Image Mode Controls - show when taskType is 'image' */}
        {isImageMode && (
          <>
            {/* Image Model Selector - using unified ModelSelector with image category */}
            {onImageModelChange && (
              <ModelSelector
                selectedModel={selectedImageModel ?? null}
                setSelectedModel={model => model && onImageModelChange(model)}
                forceOverride={false}
                setForceOverride={() => {}}
                selectedTeam={null}
                disabled={isLoading || isStreaming}
                isLoading={isImageModelsLoading}
                modelCategoryType="image"
              />
            )}

            {/* Image Size Selector */}
            {onImageSizeChange && (
              <ImageSizeSelector
                selectedSize={selectedImageSize}
                onSizeChange={onImageSizeChange}
                disabled={isLoading || isStreaming}
              />
            )}
          </>
        )}

        {/* Non-generation mode controls (chat, code, etc.) */}
        {!isGenerationMode && (
          <div
            className={
              hideSelectors ? 'flex items-center gap-2 opacity-50 pointer-events-none' : 'contents'
            }
          >
            {/* Project Selector - show when in project context */}
            {projectId && <ProjectSelectorTab projectId={projectId} disabled={hasMessages} />}

            {/* File Upload Button - show for shells that support attachments (Chat, ClaudeCode) */}
            {supportsAttachments(selectedTeam) && (
              <AttachmentButton onFileSelect={onFileSelect} disabled={isLoading || isStreaming} />
            )}

            {/* Divider between attachment and other controls */}
            {!projectId && supportsAttachments(selectedTeam) && selectedTeam && (
              <div className="w-px h-4 bg-border mx-1 flex-shrink-0" />
            )}

            {/* Team Selector - show when teams are available, onTeamChange is provided, and no messages yet */}
            {teams.length > 0 && onTeamChange && !hasMessages && (
              <TeamSelectorButton
                selectedTeam={selectedTeam}
                setSelectedTeam={(team: Team | null) => {
                  if (team) {
                    onTeamChange(team)
                  }
                }}
                teams={teams}
                disabled={isLoading || isStreaming}
                taskDetail={selectedTaskDetail}
                hideSettingsLink={false}
                currentMode={taskType}
                onTeamsRefresh={onTeamsRefresh}
              />
            )}

            {/* Skill Selector - show when skills are available */}
            {/* Skill selection is read-only after task creation (hasMessages) */}
            {availableSkills.length > 0 && onToggleSkill && (
              <SkillSelectorPopover
                ref={skillSelectorRef}
                skills={availableSkills}
                teamSkillNames={teamSkillNames}
                preloadedSkillNames={preloadedSkillNames}
                selectedSkillNames={selectedSkillNames}
                onToggleSkill={onToggleSkill}
                isChatShell={isChatShell(selectedTeam)}
                disabled={isLoading || isStreaming}
                readOnly={hasMessages}
              />
            )}

            {/* Context Selection - only show for chat shell */}
            {showChatContexts && (
              <ChatContextInput
                selectedContexts={selectedContexts}
                onContextsChange={setSelectedContexts}
                excludeKnowledgeBaseId={knowledgeBaseId}
              />
            )}

            {/* Clarification Toggle Button - only show for chat shell */}
            {isChatShell(selectedTeam) && (
              <ClarificationToggle
                enabled={enableClarification}
                onToggle={setEnableClarification}
                disabled={isLoading || isStreaming}
              />
            )}

            {/* Correction Mode Toggle Button - only show for chat shell */}
            {isChatShell(selectedTeam) && onCorrectionModeToggle && (
              <CorrectionModeToggle
                enabled={enableCorrectionMode}
                onToggle={onCorrectionModeToggle}
                disabled={isLoading || isStreaming}
                correctionModelName={correctionModelName}
                taskId={selectedTaskDetail?.id ?? null}
              />
            )}

            {/* Repository and Branch Unified Selector - show when repository selector is enabled */}
            {/* Always show when showRepositorySelector is true, let component handle the display */}
            {showRepositorySelector && (
              <UnifiedRepositorySelector
                selectedRepo={selectedRepo}
                selectedBranch={selectedBranch}
                onRepoChange={setSelectedRepo}
                onBranchChange={setSelectedBranch}
                disabled={hasMessages}
                taskDetail={selectedTaskDetail}
                compact={shouldCollapseSelectors}
                requiresWorkspace={effectiveRequiresWorkspace}
                onRequiresWorkspaceChange={hasMessages ? undefined : onRequiresWorkspaceChange}
              />
            )}

            {/* Model Selector - placed at the end of left side buttons */}
            {selectedTeam && (
              <div className={hideSelectors ? 'hidden' : ''}>
                <ModelSelector
                  selectedModel={selectedModel}
                  setSelectedModel={setSelectedModel}
                  forceOverride={forceOverride}
                  setForceOverride={setForceOverride}
                  selectedTeam={selectedTeam}
                  disabled={isLoading || isStreaming || (hasMessages && !isChatShell(selectedTeam))}
                  compact={shouldCollapseSelectors}
                  teamId={teamId}
                  taskId={taskId}
                  taskModelId={taskModelId}
                />
              </div>
            )}
          </div>
        )}
      </div>

      <div className="ml-auto flex items-center gap-2 flex-shrink-0">
        {/* Quota Usage */}
        {!shouldHideQuotaUsage && (
          <QuotaUsage className="flex-shrink-0" compact={shouldUseCompactQuota} />
        )}

        {/* Send/Stop Button */}
        {renderSendButton()}
      </div>
    </div>
  )
}

export default ChatInputControls
