import { useCallback, useEffect, useRef, useState } from 'react';
import { Pressable, ScrollView, Text, TextInput, View } from 'react-native';
import { deleteField } from 'firebase/firestore';
import { Check, Plus, X } from 'lucide-react-native';
import type { ChecklistItem, Particle } from '@/api/types';
import { particlePath, toFirestoreDocPath } from '@/lib/particle-path';
import {
  updateParticle,
  updateParticleProperties,
} from '@/lib/firestore-particles';
import { useNetwork } from '@/hooks/use-networks';
import { useSuspendPlayback } from '@/hooks/use-suspend-playback';
import { resolveHumanDisplay } from '@/lib/humans';
import { Avatar } from '@/components/Avatar';
import { cn } from '@/lib/utils';
import { useStreamSafeArea } from './stream-safe-area';

type TaskParticle = Extract<Particle, { type: 'task' }>;

interface TaskParticleViewProps {
  particle: TaskParticle;
  networkId: string;
  streamId: string;
  paused: boolean;
  onEnded: () => void;
  onProgress: (ratio: number) => void;
}

const DWELL_DURATION_S = 8;
const TICK_MS = 100;

/**
 * Editable task card. Mirrors desktop's task-particle-view — round done
 * checkbox + title, notes, a checklist, and an assignee picker — persisting
 * each edit straight to Firestore. A fixed 8s dwell auto-advances the stream;
 * focusing any field suspends playback so typing isn't raced by the timer.
 */
export function TaskParticleView({
  particle,
  networkId,
  streamId,
  paused,
  onEnded,
  onProgress,
}: TaskParticleViewProps) {
  const network = useNetwork(networkId);
  const safe = useStreamSafeArea();
  const docPath = toFirestoreDocPath(
    particlePath(networkId, [streamId, particle.id]),
  );

  const {
    title,
    notes,
    checklist = [],
    assigned_to,
    done,
  } = particle.properties;

  // Suspend the dwell timer whenever a field is focused so typing isn't
  // interrupted by an auto-advance. Mirrors desktop's `editing` suspender.
  const [editing, setEditing] = useState(false);
  useSuspendPlayback(editing, `task-edit-${particle.id}`);

  // --- Fixed dwell (mirrors TextParticleView's interval cadence) ---
  const elapsedRef = useRef(0);
  useEffect(() => {
    elapsedRef.current = 0;
    onProgress(0);
  }, [particle.id, onProgress]);

  useEffect(() => {
    if (paused) return;
    const interval = setInterval(() => {
      elapsedRef.current += TICK_MS / 1000;
      const ratio = Math.min(elapsedRef.current / DWELL_DURATION_S, 1);
      onProgress(ratio);
      if (ratio >= 1) {
        clearInterval(interval);
        onEnded();
      }
    }, TICK_MS);
    return () => clearInterval(interval);
  }, [paused, onEnded, onProgress, particle.id]);

  // Checklist writes replace the whole array; concurrent edits are
  // last-write-wins (same tradeoff desktop documents). Keep a ref so a second
  // edit composes on the latest local base before the next snapshot arrives.
  const checklistRef = useRef(checklist);
  useEffect(() => {
    checklistRef.current = checklist;
  }, [checklist]);

  const writeChecklist = useCallback(
    (items: ChecklistItem[]) => {
      checklistRef.current = items;
      return updateParticleProperties<'task'>(docPath, { checklist: items });
    },
    [docPath],
  );

  const handleToggleDone = useCallback(
    () => updateParticleProperties<'task'>(docPath, { done: !done }),
    [docPath, done],
  );

  const handleToggleItem = useCallback(
    (index: number) => {
      const items = checklistRef.current.map((item, i) =>
        i === index ? { ...item, done: !item.done } : item,
      );
      void writeChecklist(items);
    },
    [writeChecklist],
  );

  const handleCommitItemText = useCallback(
    (index: number, text: string) => {
      const items = checklistRef.current.map((item, i) =>
        i === index ? { ...item, text } : item,
      );
      void writeChecklist(items);
    },
    [writeChecklist],
  );

  const handleRemoveItem = useCallback(
    (index: number) => {
      void writeChecklist(checklistRef.current.filter((_, i) => i !== index));
    },
    [writeChecklist],
  );

  const handleAddItem = useCallback(
    (text: string) => {
      void writeChecklist([...checklistRef.current, { text, done: false }]);
    },
    [writeChecklist],
  );

  const handleAssign = useCallback(
    (humanId: string | null) => {
      if (!humanId) {
        void updateParticle(docPath, 'properties.assigned_to', deleteField());
      } else {
        void updateParticleProperties<'task'>(docPath, {
          assigned_to: humanId,
        });
      }
    },
    [docPath],
  );

  const doneCount = checklist.filter((item) => item.done).length;

  return (
    <View
      className="flex-1 items-center justify-center px-6"
      style={{ paddingTop: safe.top + 16, paddingBottom: safe.bottom + 16 }}
    >
      <ScrollView
        className="max-h-full w-full max-w-xl rounded-2xl bg-white/10"
        contentContainerClassName="px-5 py-5 gap-5"
        showsVerticalScrollIndicator
        indicatorStyle="white"
        keyboardShouldPersistTaps="handled"
      >
        {/* Title + done */}
        <View className="flex-row items-start gap-3">
          <Pressable
            onPress={handleToggleDone}
            hitSlop={8}
            accessibilityLabel={done ? 'Mark not done' : 'Mark done'}
            className={cn(
              'mt-1 h-6 w-6 items-center justify-center rounded-full border',
              done ? 'bg-emerald-500 border-emerald-500' : 'border-white/40',
            )}
          >
            {done ? <Check color="white" size={14} strokeWidth={3} /> : null}
          </Pressable>
          <TextInput
            defaultValue={title}
            key={`title-${particle.id}`}
            onFocus={() => setEditing(true)}
            onBlur={() => setEditing(false)}
            onEndEditing={(e) => {
              const value = e.nativeEvent.text;
              if (value !== title) {
                void updateParticleProperties<'task'>(docPath, {
                  title: value,
                });
              }
            }}
            placeholder="Task title"
            placeholderTextColor="rgba(255,255,255,0.3)"
            multiline
            className={cn(
              'flex-1 text-white text-2xl font-semibold',
              done && 'text-white/50 line-through',
            )}
          />
        </View>

        {/* Notes */}
        <TextInput
          defaultValue={notes ?? ''}
          key={`notes-${particle.id}`}
          onFocus={() => setEditing(true)}
          onBlur={() => setEditing(false)}
          onEndEditing={(e) => {
            const value = e.nativeEvent.text;
            if (value !== (notes ?? '')) {
              void updateParticleProperties<'task'>(docPath, { notes: value });
            }
          }}
          placeholder="Add notes…"
          placeholderTextColor="rgba(255,255,255,0.3)"
          multiline
          className="text-white/80 text-base"
        />

        {/* Checklist */}
        <View className="gap-2">
          {checklist.length > 0 ? (
            <Text className="text-white/40 text-xs">
              {doneCount} / {checklist.length} done
            </Text>
          ) : null}
          {checklist.map((item, index) => (
            <ChecklistItemRow
              key={`${particle.id}-item-${index}`}
              item={item}
              onToggle={() => handleToggleItem(index)}
              onCommitText={(text) => handleCommitItemText(index, text)}
              onRemove={() => handleRemoveItem(index)}
              onFocusChange={setEditing}
            />
          ))}
          <AddChecklistItemRow
            onAdd={handleAddItem}
            onFocusChange={setEditing}
          />
        </View>

        {/* Assignee */}
        <View className="gap-2">
          <Text className="text-white/40 text-xs">Assignee</Text>
          <ScrollView
            horizontal
            showsHorizontalScrollIndicator={false}
            contentContainerClassName="gap-2"
          >
            <AssigneeChip
              label="Unassigned"
              selected={!assigned_to}
              onPress={() => handleAssign(null)}
            />
            {network?.humans?.map((human) => {
              const display = resolveHumanDisplay(human.id, network?.humans);
              return (
                <AssigneeChip
                  key={human.id}
                  label={display.displayName}
                  selected={assigned_to === human.id}
                  onPress={() => handleAssign(human.id)}
                  avatarHumanId={human.id}
                  humans={network?.humans}
                />
              );
            })}
          </ScrollView>
        </View>
      </ScrollView>
    </View>
  );
}

function ChecklistItemRow({
  item,
  onToggle,
  onCommitText,
  onRemove,
  onFocusChange,
}: {
  item: ChecklistItem;
  onToggle: () => void;
  onCommitText: (text: string) => void;
  onRemove: () => void;
  onFocusChange: (focused: boolean) => void;
}) {
  return (
    <View className="flex-row items-center gap-2.5">
      <Pressable
        onPress={onToggle}
        hitSlop={6}
        accessibilityLabel={
          item.done ? 'Mark subtask not done' : 'Mark subtask done'
        }
        className={cn(
          'h-5 w-5 items-center justify-center rounded border',
          item.done ? 'bg-emerald-500 border-emerald-500' : 'border-white/30',
        )}
      >
        {item.done ? <Check color="white" size={12} strokeWidth={3} /> : null}
      </Pressable>
      <TextInput
        defaultValue={item.text}
        onFocus={() => onFocusChange(true)}
        onBlur={() => onFocusChange(false)}
        onEndEditing={(e) => {
          const value = e.nativeEvent.text;
          if (value !== item.text) onCommitText(value);
        }}
        placeholder="Subtask"
        placeholderTextColor="rgba(255,255,255,0.3)"
        className={cn(
          'flex-1 text-white/90 text-sm',
          item.done && 'text-white/40 line-through',
        )}
      />
      <Pressable
        onPress={onRemove}
        hitSlop={6}
        accessibilityLabel="Remove subtask"
      >
        <X color="rgba(255,255,255,0.4)" size={14} />
      </Pressable>
    </View>
  );
}

function AddChecklistItemRow({
  onAdd,
  onFocusChange,
}: {
  onAdd: (text: string) => void;
  onFocusChange: (focused: boolean) => void;
}) {
  const [draft, setDraft] = useState('');

  const submit = () => {
    const text = draft.trim();
    if (!text) return;
    onAdd(text);
    setDraft('');
  };

  return (
    <View className="flex-row items-center gap-2.5">
      <Plus color="rgba(255,255,255,0.3)" size={16} />
      <TextInput
        value={draft}
        onChangeText={setDraft}
        onFocus={() => onFocusChange(true)}
        onBlur={() => onFocusChange(false)}
        onSubmitEditing={submit}
        blurOnSubmit={false}
        placeholder="Add subtask…"
        placeholderTextColor="rgba(255,255,255,0.3)"
        className="flex-1 text-white/70 text-sm"
      />
    </View>
  );
}

function AssigneeChip({
  label,
  selected,
  onPress,
  avatarHumanId,
  humans,
}: {
  label: string;
  selected: boolean;
  onPress: () => void;
  avatarHumanId?: string;
  humans?: import('@/api/types').Human[];
}) {
  return (
    <Pressable
      onPress={onPress}
      className={cn(
        'flex-row items-center gap-2 rounded-full px-3 py-2',
        selected ? 'bg-white' : 'bg-white/10',
      )}
    >
      {avatarHumanId ? (
        <Avatar humanId={avatarHumanId} humans={humans} size="xs" />
      ) : null}
      <Text
        className={cn(
          'text-sm font-medium',
          selected ? 'text-black' : 'text-white/80',
        )}
      >
        {label}
      </Text>
    </Pressable>
  );
}
