import { PlusIcon, XIcon } from '@phosphor-icons/react'
import type { Meta, StoryFn } from '@storybook/react'
import React, { useEffect } from 'react'
import { QueryChannelAPIResponse, StreamChat } from 'stream-chat'
import { Channel, Chat, type SendButtonProps } from 'stream-chat-react'

import { createMockStreamChatClient } from '../../testing/createMockStreamChatClient'
import LockedAttachment from '../CustomMessage/LockedAttachment'
import LinkAttachment from '../LinkAttachment'

import { CustomMessageInput } from '.'

// ---------------------------------------------------------------------------
// Setup helpers (mirrors ChannelView.stories.tsx)
// ---------------------------------------------------------------------------

const mockUser = {
  id: 'storybook-user',
  name: 'Storybook User',
  image: 'https://i.pravatar.cc/150?img=1',
}

const mockParticipant = {
  id: 'participant-1',
  name: 'Jane Creator',
  image: 'https://i.pravatar.cc/150?img=5',
}

const createMockChannel = async (
  client: StreamChat,
  opts: { frozen?: boolean } = {}
) => {
  const channelData = {
    members: [mockUser.id, mockParticipant.id],
    frozen: opts.frozen ?? false,
  }
  const ch = client.channel('messaging', 'storybook-cmi-channel', channelData)

  ch.watch = async () => {
    ch.state.members = {
      [mockUser.id]: { user: mockUser, user_id: mockUser.id },
      [mockParticipant.id]: {
        user: mockParticipant,
        user_id: mockParticipant.id,
      },
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    ;(ch as any)._data = channelData
    return {
      channel: channelData,
      members: [],
      messages: [],
      watchers: [],
      pinned_messages: [],
      duration: '0ms',
    } as unknown as QueryChannelAPIResponse
  }

  try {
    await ch.watch()
  } catch (_) {
    /* mock */
  }
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  ;(ch as any)._data = channelData
  return ch
}

// ---------------------------------------------------------------------------
// Story wrapper — mounts the input inside a real Stream Channel context
// ---------------------------------------------------------------------------

type WrapperProps = {
  frozen?: boolean
  renderActions?: () => React.ReactNode
  sendButton?: React.ComponentType<SendButtonProps>
  attachmentPreviewList?: React.ComponentType
  renderFooter?: () => React.ReactNode
  /**
   * Stands in for a host that publishes `--messaging-surface-height` — the
   * keyboard-shrunk viewport height the composer caps itself against. Set it to
   * pin the cap to a known value instead of leaving it viewport-relative.
   */
  surfaceHeight?: number
}

const Wrapper: React.FC<WrapperProps> = (props) => {
  const {
    frozen,
    renderActions,
    sendButton,
    attachmentPreviewList,
    renderFooter,
    surfaceHeight,
  } = props

  const [client] = React.useState(() => createMockStreamChatClient(mockUser))

  const [channel, setChannel] = React.useState<ReturnType<
    StreamChat['channel']
  > | null>(null)

  useEffect(() => {
    createMockChannel(client, { frozen }).then(setChannel)
  }, [client, frozen])

  if (!channel) return <div className="p-4 text-sm text-gray-400">Loading…</div>

  return (
    <Chat client={client}>
      <Channel
        channel={channel}
        {...(sendButton ? { SendButton: sendButton } : {})}
        {...(attachmentPreviewList
          ? { AttachmentPreviewList: attachmentPreviewList }
          : {})}
      >
        <div
          className="bg-white"
          style={
            {
              minWidth: 360,
              // Bottom-anchored inside a fixed-height surface, the way the host
              // lays the composer out under a raised keyboard.
              ...(surfaceHeight && {
                height: surfaceHeight,
                '--messaging-surface-height': `${surfaceHeight}px`,
                display: 'flex',
                flexDirection: 'column',
                justifyContent: 'flex-end',
              }),
            } as React.CSSProperties
          }
        >
          <CustomMessageInput
            renderActions={renderActions}
            renderFooter={renderFooter}
          />
        </div>
      </Channel>
    </Chat>
  )
}

// ---------------------------------------------------------------------------
// Meta
// ---------------------------------------------------------------------------

const meta: Meta<WrapperProps> = {
  title: 'CustomMessageInput',
  component: CustomMessageInput,
  parameters: {
    layout: 'centered',
  },
}
export default meta

// ---------------------------------------------------------------------------
// Stories
// ---------------------------------------------------------------------------

export const Default: StoryFn<WrapperProps> = (args) => <Wrapper {...args} />
Default.args = {}
Default.parameters = {
  docs: {
    description: {
      story:
        'Default message input. The send button (arrow) is disabled until the user types text — `useMessageComposerHasSendableData` controls this.',
    },
  },
}

export const Frozen: StoryFn<WrapperProps> = (args) => <Wrapper {...args} />
Frozen.args = { frozen: true }
Frozen.parameters = {
  docs: {
    description: {
      story:
        'Frozen channel state: the entire input area fades out (`aria-disabled`, `inert`), the textarea becomes read-only, and the send button is disabled.',
    },
  },
}

export const WithCustomActionButton: StoryFn<WrapperProps> = (args) => (
  <Wrapper {...args} />
)
WithCustomActionButton.args = {
  renderActions: () => (
    <button
      type="button"
      aria-label="Attach media"
      className="flex items-center justify-center size-10 rounded-full bg-[#F1F0EE] hover:bg-[#E5E4E1] shrink-0"
      onClick={() => console.log('media picker')}
    >
      📷
    </button>
  ),
}
WithCustomActionButton.parameters = {
  docs: {
    description: {
      story:
        'Shows how `renderActions` injects extra controls (e.g. a media picker button) to the left of the message bubble.',
    },
  },
}

/** A custom send button that turns purple to signal a media attachment is staged. */
const PurpleMediaSendButton: React.FC<SendButtonProps> = (props) => {
  const { sendMessage, disabled, ...rest } = props
  return (
    <button
      {...rest}
      type="button"
      aria-label="Send"
      disabled={disabled}
      onClick={sendMessage}
      className="str-chat__send-button mt-auto flex items-center justify-center shrink-0 rounded-full size-8 bg-[#6D28D9] disabled:bg-[#F1F0EE] disabled:text-black/20 text-white"
      style={{ fontSize: 15 }}
    >
      🚀
    </button>
  )
}

export const WithCustomSendButton: StoryFn<WrapperProps> = (args) => (
  <Wrapper {...args} />
)
WithCustomSendButton.args = { sendButton: PurpleMediaSendButton }
WithCustomSendButton.parameters = {
  docs: {
    description: {
      story:
        "Passes a custom `SendButton` via `Channel`'s `SendButton` prop (which is how `ChannelView`'s `sendButton` prop surfaces it). `CustomMessageInput` reads the button from `useComponentContext` and falls back to the default when none is provided.",
    },
  },
}

export const WithAttachments: StoryFn<WrapperProps> = (args) => (
  <Wrapper {...args} />
)
WithAttachments.args = {
  attachmentPreviewList: () => (
    <div className="relative size-20 shrink-0 overflow-hidden rounded-2xl border border-black/8">
      <img
        src="https://picsum.photos/seed/attachment/160/160"
        alt="Staged attachment"
        className="size-full object-cover"
      />
    </div>
  ),
  renderActions: () => (
    <button
      type="button"
      aria-label="Add attachment"
      onClick={() => console.log('add attachment')}
      className="flex items-center justify-center size-12 rounded-full bg-[#F1F0EE] hover:bg-[#E5E4E1]"
    >
      <PlusIcon className="size-5" weight="bold" />
    </button>
  ),
}
WithAttachments.parameters = {
  docs: {
    description: {
      story:
        "Message input with a regular image attachment staged. In production thumbnails are portaled into `.central-container` by `ComposerPendingMediaPortal`; here we use `Channel`'s `AttachmentPreviewList` override to achieve the same visual placement via the React tree.",
    },
  },
}

export const WithStagedLinkPreviewUnderKeyboard: StoryFn<WrapperProps> = (
  args
) => <Wrapper {...args} />
WithStagedLinkPreviewUnderKeyboard.args = {
  // Roughly a 393x852 phone with the soft keyboard up, so the 250px staged card
  // alone outgrows the composer's cap (half of this) and the card scrolls.
  surfaceHeight: 516,
  attachmentPreviewList: () => (
    <LinkAttachment.Composer
      title="How to run your first marathon"
      url="https://example.com/marathon"
      thumbnailUrl="https://picsum.photos/seed/marathon/580/300"
      onDismiss={() => console.log('dismiss link preview')}
    />
  ),
}
WithStagedLinkPreviewUnderKeyboard.parameters = {
  docs: {
    description: {
      story:
        'MES-1037: with a link preview staged the composer used to grow tall enough for the soft keyboard to cover the textarea and send button. The white card is now capped at half `--messaging-surface-height` (the keyboard-shrunk height its host publishes) and scrolls as ONE region — the preview keeps its full height instead of being cropped to make room, and the send button sticks to the bottom of the scroll so a long message cannot carry it out of view.',
    },
  },
}

export const WithPaidAttachment: StoryFn<WrapperProps> = (args) => (
  <Wrapper {...args} />
)
WithPaidAttachment.args = {
  attachmentPreviewList: () => (
    <LockedAttachment
      isPreview
      contentType="media"
      title="Exclusive Content"
      mimeType="image/jpeg"
      thumbnailUrl="https://picsum.photos/seed/paid/320/180"
      detail="3.2 MB"
      amountText="AU$9.99"
      onDismiss={() => console.log('dismiss paid attachment')}
      onEditClick={() => console.log('edit paid attachment')}
    />
  ),
  renderActions: () => (
    <button
      type="button"
      aria-label="Add attachment"
      onClick={() => console.log('add attachment')}
      className="flex items-center justify-center size-12 rounded-full bg-[#F1F0EE] hover:bg-[#E5E4E1]"
    >
      <PlusIcon className="size-5" weight="bold" />
    </button>
  ),
  renderFooter: () => (
    <div className="flex items-center justify-between gap-2 rounded-lg bg-[#E8EEFF] px-4 py-3 text-sm text-black/70">
      <span>Tap to add a price</span>
      <button
        type="button"
        aria-label="Dismiss"
        className="flex shrink-0 items-center justify-center text-black/40 hover:text-black/70 bg-black/10 rounded-full p-1"
      >
        <XIcon className="size-4" />
      </button>
    </div>
  ),
}
WithPaidAttachment.parameters = {
  docs: {
    description: {
      story:
        "Message input with a paid attachment staged inside the input bubble. Uses `Channel`'s `AttachmentPreviewList` override to render a `LockedAttachment isPreview` card at the top of the input. `onDismiss` removes it; `onEditClick` reopens the paid content wizard.",
    },
  },
}
