import {
  getMentionAt,
  insertMentionAt,
  resolveMentionFacets,
  segmentByFacets,
} from '@crumbs/core/mentions'
import {
  TRAIL_POST_MAX,
  TrailPostTextSchema,
} from '@crumbs/core/schemas'
import {useLocalSearchParams} from 'expo-router'
import {useMemo, useRef, useState} from 'react'
import {Text, View, type TextInputProps} from 'react-native'

import {AuthGate} from '@/components/auth-gate'
import {
  CharProgress,
  ComposerSheet,
  ComposerTextInput,
  MentionAutocomplete,
  type MentionCandidate,
} from '@/components/composer'
import {FormError} from '@/components/forms/form-error'
import {Button} from '@/components/ui/button'
import {useSubmitAction} from '@/hooks/use-submit-action'
import {goBack} from '@/lib/navigation'
import {useTheme} from '@/sprinkles'
import {createTrailPost} from '@/stores/trail-posts'
import {useTrail} from '@/stores/trails'

export default function NewTrailPostScreen() {
  return (
    <AuthGate>
      <NewTrailPostScreenInner />
    </AuthGate>
  )
}

function NewTrailPostScreenInner() {
  const t = useTheme()
  const {trailId} = useLocalSearchParams<{trailId: string}>()
  const trail = useTrail(trailId)
  const [text, setText] = useState('')
  const {submitting, error, submit} = useSubmitAction(
    async (body: string) => {
      await createTrailPost(trailId, body)
      goBack()
    },
  )
  const [mentionPrefix, setMentionPrefix] = useState<string | null>(
    null,
  )
  // updated by onSelectionChange, read on the next keystroke; a ref so
  // cursor moves don't re-render (fires before onChangeText settles)
  const cursorRef = useRef(0)

  const candidates = useMemo<MentionCandidate[]>(
    () =>
      trail
        ? [
            {
              id: trail.authorId,
              handle: trail.authorHandle,
              avatarUrl: trail.authorAvatarUrl,
            },
            ...trail.collaborators.map((c) => ({
              id: c.id,
              handle: c.handle,
              avatarUrl: c.avatarUrl,
            })),
          ]
        : [],
    [trail],
  )

  const parsed = TrailPostTextSchema.safeParse(text)
  const valid = parsed.success

  // facets are re-derived from scratch on every change (never patched),
  // so edits inside a mention just work
  const segments = segmentByFacets(
    text,
    resolveMentionFacets(text, candidates),
  )

  const handleChangeText = (next: string) => {
    setText(next)
    // onChangeText fires before onSelectionChange; clamp so deletes
    // can't leave the cursor past the end
    const cursor = Math.min(cursorRef.current, next.length)
    setMentionPrefix(getMentionAt(next, cursor)?.value ?? null)
  }

  const handleSelectionChange: TextInputProps['onSelectionChange'] = (
    e,
  ) => {
    cursorRef.current = e.nativeEvent.selection.start
  }

  const handleSelectMention = (handle: string) => {
    const cursor = Math.min(cursorRef.current, text.length)
    setText(insertMentionAt(text, cursor, handle))
    setMentionPrefix(null)
  }

  const handleSubmit = () => {
    if (parsed.success) void submit(parsed.data)
  }

  return (
    <>
      <ComposerSheet
        title="New post"
        onCancel={goBack}
        submit={
          <Button
            label={submitting ? 'Posting…' : 'Post'}
            color="primary"
            size="small"
            onPress={handleSubmit}
            disabled={!valid || submitting}
          />
        }
        toolbar={
          <>
            <View />
            <CharProgress count={text.length} max={TRAIL_POST_MAX} />
          </>
        }
      >
        <ComposerTextInput
          value={text}
          onChangeText={handleChangeText}
          onSelectionChange={handleSelectionChange}
          placeholder="Write a post"
          maxLength={TRAIL_POST_MAX}
          autoFocus
        >
          <Text>
            {segments.map((segment, i) => (
              <Text
                key={i}
                style={
                  segment.facet && {color: t.palette.primary_500}
                }
              >
                {segment.text}
              </Text>
            ))}
          </Text>
        </ComposerTextInput>
        {error && <FormError error={error} />}
        {mentionPrefix != null && (
          <MentionAutocomplete
            prefix={mentionPrefix}
            candidates={candidates}
            onSelect={handleSelectMention}
          />
        )}
      </ComposerSheet>
    </>
  )
}
