import type { Meta, StoryFn } from '@storybook/react'
import React from 'react'
import type { Event } from 'stream-chat'
import {
  AIStates,
  ChannelStateProvider,
  ChatProvider,
  TypingProvider,
} from 'stream-chat-react'

import { DmAgentEnabledContext } from './DmAgentContext'

import CustomTypingIndicator from '.'

type StoryProps = {
  typingEventsEnabled?: boolean
  typing?: Record<string, Event>
  aiState?: string
  dmAgentEnabled?: boolean
}

const currentUser = {
  id: 'visitor-1',
  name: 'Visitor',
}

const typingUser = {
  id: 'creator-1',
  name: 'Creator',
  image: 'https://i.pravatar.cc/48?img=5',
}

const defaultTyping: Record<string, Event> = {
  [typingUser.id]: {
    type: 'typing.start',
    user: typingUser,
    parent_id: undefined,
  } as Event,
}

type ListenerMap = Record<
  string,
  (event: { ai_state: string; cid: string }) => void
>

const createMockChannel = ({ aiState }: { aiState?: string }) => {
  const listeners: ListenerMap = {}
  const channel = {
    cid: 'messaging:test',
    state: {
      members: {
        [currentUser.id]: { user: currentUser },
        [typingUser.id]: { user: typingUser },
      },
    },
    on(eventType: string, handler: ListenerMap[string]) {
      listeners[eventType] = handler
      // Fire the requested AI state synchronously so the hook picks it up.
      if (eventType === 'ai_indicator.update' && aiState) {
        handler({ ai_state: aiState, cid: 'messaging:test' })
      }
      return { unsubscribe: () => {} }
    },
  }
  return channel
}

const StoryWrapper: React.FC<StoryProps> = ({
  typingEventsEnabled = true,
  typing = {},
  aiState,
  dmAgentEnabled = true,
}) => {
  const channel = createMockChannel({ aiState })

  const chatContextValue = {
    client: {
      user: currentUser,
    },
    theme: 'str-chat__theme-light',
    channelsQueryState: {
      error: null,
      queryInProgress: null,
    },
    latestMessageDatesByChannels: {},
    mutes: [],
    closeMobileNav: () => {},
    openMobileNav: () => {},
    getAppSettings: () => null,
    setActiveChannel: () => {},
    themeVersion: '2',
    useImageFlagEmojisOnWindows: false,
  }

  const channelStateValue = {
    channel,
    channelCapabilities: {},
    channelConfig: {
      typing_events: typingEventsEnabled,
    },
    imageAttachmentSizeHandler: () => ({}),
    multipleUploads: false,
    notifications: [],
    shouldGenerateVideoThumbnail: false,
    suppressAutoscroll: false,
    videoAttachmentSizeHandler: () => ({}),
  }

  return (
    <ChatProvider value={chatContextValue as never}>
      <ChannelStateProvider value={channelStateValue as never}>
        <TypingProvider value={{ typing }}>
          <DmAgentEnabledContext.Provider value={dmAgentEnabled}>
            <div className="relative h-20 w-[200px] bg-[#f4f4f4] p-3">
              <CustomTypingIndicator />
            </div>
          </DmAgentEnabledContext.Provider>
        </TypingProvider>
      </ChannelStateProvider>
    </ChatProvider>
  )
}

const meta: Meta<StoryProps> = {
  title: 'CustomTypingIndicator',
  component: CustomTypingIndicator,
  parameters: {
    layout: 'centered',
    // CustomTypingIndicator is animation-dominant (SMIL spinner + DOM
    // appear/disappear on typing-state transitions). Even with the SMIL
    // pause decorator, a snapshot here is mostly testing what frame the
    // animation paused at — low value for visual regression, high flake
    // potential. Skip it in Chromatic; the stories stay browsable in
    // Storybook for design review.
    chromatic: { disableSnapshot: true },
  },
}
export default meta

export const Default: StoryFn<StoryProps> = (args) => <StoryWrapper {...args} />
Default.args = {
  typing: defaultTyping,
}

export const HiddenWhenNoTyping: StoryFn<StoryProps> = (args) => (
  <StoryWrapper {...args} />
)
HiddenWhenNoTyping.args = {
  typing: {},
}

export const AiAgentThinking: StoryFn<StoryProps> = (args) => (
  <StoryWrapper {...args} />
)
AiAgentThinking.args = {
  aiState: AIStates.Thinking,
}

export const AiAgentGenerating: StoryFn<StoryProps> = (args) => (
  <StoryWrapper {...args} />
)
AiAgentGenerating.args = {
  aiState: AIStates.Generating,
}
