import { useState, useRef, useEffect, useCallback } from 'react'
import {
  IconBold, IconItalic, IconStrikethrough, IconLink, IconCode,
  IconList, IconListNumbers, IconQuote, IconPhoto, IconTable,
  IconH1, IconH2, IconH3, IconMinus, IconCheckbox, IconSourceCode,
  IconEye, IconPencil,
} from '@tabler/icons-react'
import Markdown from './Markdown'
import Avatar from './Avatar'
import { api } from '../lib/api'

interface MentionUser {
  id: string
  username: string
  avatarUrl: string | null
}

interface Props {
  value: string
  onChange: (value: string) => void
  placeholder?: string
  rows?: number
  autoFocus?: boolean
  preview?: boolean
  ariaRequired?: boolean
  ariaLabel?: string
  mentions?: boolean
  onPaste?: () => void
}

type Action =
  | { prefix: string; suffix: string }
  | { linePrefix: string }
  | { block: string }

interface ToolbarItem {
  icon: typeof IconBold
  title: string
  action: Action
}

type ToolbarEntry = ToolbarItem | 'table'
type ToolbarGroup = ToolbarEntry[]

const toolbar: ToolbarGroup[] = [
  [
    { icon: IconH1, title: 'Heading 1', action: { linePrefix: '# ' } },
    { icon: IconH2, title: 'Heading 2', action: { linePrefix: '## ' } },
    { icon: IconH3, title: 'Heading 3', action: { linePrefix: '### ' } },
  ],
  [
    { icon: IconBold, title: 'Bold', action: { prefix: '**', suffix: '**' } },
    { icon: IconItalic, title: 'Italic', action: { prefix: '*', suffix: '*' } },
    { icon: IconStrikethrough, title: 'Strikethrough', action: { prefix: '~~', suffix: '~~' } },
  ],
  [
    { icon: IconCode, title: 'Inline code', action: { prefix: '`', suffix: '`' } },
    { icon: IconSourceCode, title: 'Code block', action: { block: '```\n\n```' } },
    { icon: IconQuote, title: 'Blockquote', action: { linePrefix: '> ' } },
  ],
  [
    { icon: IconList, title: 'Bullet list', action: { linePrefix: '- ' } },
    { icon: IconListNumbers, title: 'Numbered list', action: { linePrefix: '1. ' } },
    { icon: IconCheckbox, title: 'Task list', action: { linePrefix: '- [ ] ' } },
  ],
  [
    { icon: IconLink, title: 'Link', action: { prefix: '[', suffix: '](url)' } },
    { icon: IconPhoto, title: 'Image', action: { prefix: '![', suffix: '](url)' } },
    { icon: IconMinus, title: 'Horizontal rule', action: { block: '---' } },
    'table',
  ],
]

const GRID_COLS = 8
const GRID_ROWS = 6
const CELL = 44
const GAP = 1

function buildTable(cols: number, rows: number): string {
  const header = '| ' + Array.from({ length: cols }, (_, i) => `Column ${i + 1}`).join(' | ') + ' |'
  const sep = '| ' + Array.from({ length: cols }, () => '---').join(' | ') + ' |'
  const dataRows = Array.from({ length: rows }, () =>
    '| ' + Array.from({ length: cols }, () => ' ').join(' | ') + ' |'
  )
  return [header, sep, ...dataRows].join('\n')
}

function TablePicker({ onSelect, onClose }: { onSelect: (cols: number, rows: number) => void; onClose: () => void }) {
  const [hover, setHover] = useState<[number, number]>([0, 0])
  const popRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const handler = (e: MouseEvent) => {
      if (popRef.current && !popRef.current.contains(e.target as Node)) onClose()
    }
    document.addEventListener('mousedown', handler)
    return () => document.removeEventListener('mousedown', handler)
  }, [onClose])

  return (
    <div
      ref={popRef}
      className="absolute z-50"
      style={{
        top: '100%',
        left: 0,
        marginTop: 4,
        background: 'var(--surface)',
        border: '1px solid var(--border)',
        borderRadius: 'var(--radius-md)',
        boxShadow: 'var(--shadow-lg)',
        padding: 8,
      }}
    >
      <div
        style={{
          display: 'grid',
          gridTemplateColumns: `repeat(${GRID_COLS}, ${CELL}px)`,
          gap: GAP,
        }}
      >
        {Array.from({ length: GRID_ROWS * GRID_COLS }, (_, i) => {
          const col = i % GRID_COLS
          const row = Math.floor(i / GRID_COLS)
          const active = col < hover[0] && row < hover[1]
          return (
            <button
              key={i}
              type="button"
              aria-label={`${col + 1} by ${row + 1} table`}
              onMouseEnter={() => setHover([col + 1, row + 1])}
              onFocus={() => setHover([col + 1, row + 1])}
              onClick={() => { onSelect(col + 1, row + 1); onClose() }}
              style={{
                width: CELL,
                height: CELL,
                borderRadius: 3,
                border: active ? '1px solid var(--accent)' : '1px solid var(--border)',
                background: active ? 'var(--accent-subtle)' : 'transparent',
                cursor: 'pointer',
                padding: 0,
                transition: 'background 60ms ease-out, border-color 60ms ease-out',
              }}
            />
          )
        })}
      </div>
      <div
        className="text-center mt-1.5"
        style={{ color: 'var(--text-tertiary)', fontSize: 'var(--text-xs)' }}
      >
        {hover[0] > 0 && hover[1] > 0 ? `${hover[0]} x ${hover[1]}` : 'Select size'}
      </div>
    </div>
  )
}

export default function MarkdownEditor({ value, onChange, placeholder, rows = 3, autoFocus, preview: enablePreview, ariaRequired, ariaLabel, mentions: enableMentions, onPaste }: Props) {
  const ref = useRef<HTMLTextAreaElement>(null)
  const [previewing, setPreviewing] = useState(false)
  const [tablePicker, setTablePicker] = useState(false)
  const [mentionUsers, setMentionUsers] = useState<MentionUser[]>([])
  const [mentionActive, setMentionActive] = useState(0)
  const mentionDebounce = useRef<ReturnType<typeof setTimeout>>()
  const mentionDropdownRef = useRef<HTMLDivElement>(null)
  const [mentionQuery, setMentionQuery] = useState('')

  const getMentionQuery = useCallback((): string | null => {
    const ta = ref.current
    if (!ta || !enableMentions) return null
    const pos = ta.selectionStart
    const before = value.slice(0, pos)
    const match = before.match(/@([a-zA-Z0-9_]{2,30})$/)
    return match ? match[1] : null
  }, [value, enableMentions])

  useEffect(() => {
    if (!enableMentions) return
    const q = getMentionQuery()
    if (!q || q.length < 2) {
      setMentionUsers([])
      setMentionQuery('')
      return
    }
    if (q === mentionQuery) return
    setMentionQuery(q)
    if (mentionDebounce.current) clearTimeout(mentionDebounce.current)
    mentionDebounce.current = setTimeout(() => {
      api.get<{ users: MentionUser[] }>(`/users/search?q=${encodeURIComponent(q)}`)
        .then((r) => { setMentionUsers(r.users); setMentionActive(0) })
        .catch(() => setMentionUsers([]))
    }, 200)
    return () => { if (mentionDebounce.current) clearTimeout(mentionDebounce.current) }
  }, [value, getMentionQuery, enableMentions])

  const insertMention = (username: string) => {
    const ta = ref.current
    if (!ta) return
    const pos = ta.selectionStart
    const before = value.slice(0, pos)
    const after = value.slice(pos)
    const atIdx = before.lastIndexOf('@')
    if (atIdx === -1) return
    const newVal = before.slice(0, atIdx) + '@' + username + ' ' + after
    onChange(newVal)
    setMentionUsers([])
    setMentionQuery('')
    const newPos = atIdx + username.length + 2
    requestAnimationFrame(() => { ta.focus(); ta.setSelectionRange(newPos, newPos) })
  }

  useEffect(() => {
    if (!enableMentions) return
    const handler = (e: MouseEvent) => {
      if (mentionDropdownRef.current && !mentionDropdownRef.current.contains(e.target as Node)) {
        setMentionUsers([])
      }
    }
    document.addEventListener('mousedown', handler)
    return () => document.removeEventListener('mousedown', handler)
  }, [enableMentions])

  const insertBlock = (block: string) => {
    const ta = ref.current
    if (!ta) return
    const start = ta.selectionStart
    const end = ta.selectionEnd
    const before = value.slice(0, start)
    const after = value.slice(end)
    const needsBefore = before.length > 0 && !before.endsWith('\n\n')
    const needsAfter = after.length > 0 && !after.startsWith('\n')
    const prefix = needsBefore ? (before.endsWith('\n') ? '\n' : '\n\n') : ''
    const suffix = needsAfter ? '\n' : ''
    const newValue = before + prefix + block + suffix + after
    const firstNewline = block.indexOf('\n')
    const blockStart = before.length + prefix.length
    const cursorPos = firstNewline > -1 ? blockStart + firstNewline + 1 : blockStart + block.length
    onChange(newValue)
    requestAnimationFrame(() => {
      ta.focus()
      ta.setSelectionRange(cursorPos, cursorPos)
    })
  }

  const apply = (action: Action) => {
    const ta = ref.current
    if (!ta) return

    const start = ta.selectionStart
    const end = ta.selectionEnd
    const selected = value.slice(start, end)

    let newValue: string
    let cursorPos: number

    if ('block' in action) {
      insertBlock(action.block)
      return
    } else if ('linePrefix' in action) {
      const lines = selected ? selected.split('\n') : ['']
      const prefixed = lines.map((l) => action.linePrefix + l).join('\n')
      newValue = value.slice(0, start) + prefixed + value.slice(end)
      cursorPos = start + prefixed.length
    } else {
      const wrapped = action.prefix + (selected || 'text') + action.suffix
      newValue = value.slice(0, start) + wrapped + value.slice(end)
      if (selected) {
        cursorPos = start + wrapped.length
      } else {
        cursorPos = start + action.prefix.length + 4
      }
    }

    onChange(newValue)
    requestAnimationFrame(() => {
      ta.focus()
      if (!selected && 'prefix' in action && 'suffix' in action) {
        ta.setSelectionRange(start + action.prefix.length, start + action.prefix.length + 4)
      } else {
        ta.setSelectionRange(cursorPos, cursorPos)
      }
    })
  }

  const btnStyle = {
    color: 'var(--text-tertiary)',
    borderRadius: 'var(--radius-sm)',
    transition: 'color var(--duration-fast) ease-out, background var(--duration-fast) ease-out',
  }

  const hover = (e: React.MouseEvent<HTMLButtonElement> | React.FocusEvent<HTMLButtonElement>, enter: boolean) => {
    e.currentTarget.style.color = enter ? 'var(--text)' : 'var(--text-tertiary)'
    e.currentTarget.style.background = enter ? 'var(--surface-hover)' : 'transparent'
  }

  return (
    <div>
      <div
        className="flex items-center gap-0.5 mb-1.5 px-1 flex-wrap"
        style={{ minHeight: 28 }}
      >
        {toolbar.map((group, gi) => (
          <div key={gi} className="flex items-center gap-0.5">
            {gi > 0 && (
              <div
                style={{
                  width: 1,
                  height: 16,
                  background: 'var(--border)',
                  margin: '0 4px',
                  flexShrink: 0,
                }}
              />
            )}
            {group.map((entry) => {
              if (entry === 'table') {
                return (
                  <div key="table" className="relative">
                    <button
                      type="button"
                      title="Table"
                      aria-label="Table"
                      onClick={() => { setPreviewing(false); setTablePicker(!tablePicker) }}
                      className="w-11 h-11 flex items-center justify-center"
                      style={{
                        ...btnStyle,
                        color: tablePicker ? 'var(--accent)' : 'var(--text-tertiary)',
                      }}
                      onMouseEnter={(e) => hover(e, true)}
                      onMouseLeave={(e) => {
                        e.currentTarget.style.color = tablePicker ? 'var(--accent)' : 'var(--text-tertiary)'
                        e.currentTarget.style.background = 'transparent'
                      }}
                      onFocus={(e) => hover(e, true)}
                      onBlur={(e) => {
                        e.currentTarget.style.color = tablePicker ? 'var(--accent)' : 'var(--text-tertiary)'
                        e.currentTarget.style.background = 'transparent'
                      }}
                    >
                      <IconTable size={14} stroke={2} />
                    </button>
                    {tablePicker && (
                      <TablePicker
                        onSelect={(cols, rows) => {
                          setPreviewing(false)
                          insertBlock(buildTable(cols, rows))
                        }}
                        onClose={() => setTablePicker(false)}
                      />
                    )}
                  </div>
                )
              }
              const { icon: Icon, title, action } = entry
              return (
                <button
                  key={title}
                  type="button"
                  title={title}
                  aria-label={title}
                  onClick={() => { setPreviewing(false); apply(action) }}
                  className="w-11 h-11 flex items-center justify-center"
                  style={btnStyle}
                  onMouseEnter={(e) => hover(e, true)}
                  onMouseLeave={(e) => hover(e, false)}
                  onFocus={(e) => hover(e, true)}
                  onBlur={(e) => hover(e, false)}
                >
                  <Icon size={14} stroke={2} />
                </button>
              )
            })}
          </div>
        ))}

        {enablePreview && (
          <>
            <div
              style={{
                width: 1,
                height: 16,
                background: 'var(--border)',
                margin: '0 4px',
                flexShrink: 0,
              }}
            />
            <button
              type="button"
              title={previewing ? 'Edit' : 'Preview'}
              aria-label={previewing ? 'Edit' : 'Preview'}
              onClick={() => setPreviewing(!previewing)}
              className="w-11 h-11 flex items-center justify-center"
              style={{
                ...btnStyle,
                color: previewing ? 'var(--accent)' : 'var(--text-tertiary)',
              }}
              onMouseEnter={(e) => hover(e, true)}
              onMouseLeave={(e) => {
                e.currentTarget.style.color = previewing ? 'var(--accent)' : 'var(--text-tertiary)'
                e.currentTarget.style.background = 'transparent'
              }}
              onFocus={(e) => hover(e, true)}
              onBlur={(e) => {
                e.currentTarget.style.color = previewing ? 'var(--accent)' : 'var(--text-tertiary)'
                e.currentTarget.style.background = 'transparent'
              }}
            >
              {previewing ? <IconPencil size={14} stroke={2} /> : <IconEye size={14} stroke={2} />}
            </button>
          </>
        )}
      </div>

      {previewing ? (
        <div
          className="input w-full"
          style={{
            minHeight: rows * 24 + 24,
            padding: '12px 14px',
            overflow: 'auto',
            resize: 'vertical',
          }}
        >
          {value.trim() ? (
            <Markdown>{value}</Markdown>
          ) : (
            <span style={{ color: 'var(--text-tertiary)', fontSize: 'var(--text-sm)' }}>
              Nothing to preview
            </span>
          )}
        </div>
      ) : (
        <div style={{ position: 'relative' }}>
          <textarea
            ref={ref}
            className="input w-full"
            placeholder={placeholder}
            rows={rows}
            value={value}
            onChange={(e) => onChange(e.target.value)}
            onKeyDown={enableMentions && mentionUsers.length > 0 ? (e) => {
              if (e.key === 'ArrowDown') { e.preventDefault(); setMentionActive((a) => (a + 1) % mentionUsers.length) }
              else if (e.key === 'ArrowUp') { e.preventDefault(); setMentionActive((a) => (a - 1 + mentionUsers.length) % mentionUsers.length) }
              else if ((e.key === 'Enter' || e.key === 'Tab') && mentionUsers[mentionActive]) { e.preventDefault(); insertMention(mentionUsers[mentionActive].username) }
              else if (e.key === 'Escape') { setMentionUsers([]); setMentionQuery('') }
            } : undefined}
            onPaste={onPaste}
            style={{ resize: 'vertical' }}
            autoFocus={autoFocus}
            aria-label={ariaLabel || 'Markdown content'}
            aria-required={ariaRequired || undefined}
          />
          {enableMentions && mentionUsers.length > 0 && (
            <div
              ref={mentionDropdownRef}
              role="listbox"
              aria-label="Mention suggestions"
              style={{
                position: 'absolute',
                left: 0,
                bottom: -4,
                transform: 'translateY(100%)',
                zIndex: 50,
                background: 'var(--surface)',
                border: '1px solid var(--border)',
                borderRadius: 'var(--radius-md)',
                boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
                minWidth: 200,
                maxHeight: 240,
                overflow: 'auto',
              }}
            >
              {mentionUsers.map((u, i) => (
                <button
                  key={u.id}
                  role="option"
                  aria-selected={i === mentionActive}
                  onClick={() => insertMention(u.username)}
                  className="flex items-center gap-2 w-full px-3"
                  style={{
                    minHeight: 44,
                    background: i === mentionActive ? 'var(--surface-hover)' : 'transparent',
                    border: 'none',
                    cursor: 'pointer',
                    fontSize: 'var(--text-sm)',
                    color: 'var(--text)',
                    textAlign: 'left',
                  }}
                  onMouseEnter={() => setMentionActive(i)}
                >
                  <Avatar userId={u.id} name={u.username} avatarUrl={u.avatarUrl} size={22} />
                  <span>@{u.username}</span>
                </button>
              ))}
            </div>
          )}
        </div>
      )}
    </div>
  )
}
