import { useCallback, useEffect, useRef, useState } from 'react';
import { deleteField } from 'firebase/firestore';
import { Plus, X } from 'lucide-react';
import type { ChecklistItem, Particle } from '@/api/types';
import {
  particlePath,
  parseParticlePath,
  toFirestoreDocPath,
  type ParticlePath,
} from '@/lib/particle-path';
import {
  updateParticle,
  updateParticleProperties,
} from '@/lib/firestore-particles';
import { cn } from '@/lib/utils';
import { Checkbox } from '@/components/ui/checkbox';
import { Textarea } from '@/components/ui/textarea';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { HumanAvatar } from '@/components/human-avatar';
import { useNetwork } from '@/hooks/use-networks';
import { useFixedDwell } from '@/hooks/use-fixed-dwell';
import { useLiveDraftField } from '@/hooks/use-live-draft-field';
import { useSuspendPlayback } from '@/hooks/use-suspend-playback';
import { resolveHumanDisplay } from '@/lib/humans';

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

interface TaskParticleViewProps {
  particle: TaskParticle;
  containerPath: ParticlePath;
  paused: boolean;
  onEnded: () => void;
  onProgress?: (ratio: number) => void;
}

const DWELL_DURATION_S = 8;
const UNASSIGNED = 'unassigned';

function useParticleDocPath(
  containerPath: ParticlePath,
  particleId: string,
): string {
  const { networkId, segments } = parseParticlePath(containerPath);
  return toFirestoreDocPath(particlePath(networkId, [...segments, particleId]));
}

export function TaskParticleView({
  particle,
  containerPath,
  paused,
  onEnded,
  onProgress,
}: TaskParticleViewProps) {
  const { networkId } = parseParticlePath(containerPath);
  const network = useNetwork(networkId);
  const docPath = useParticleDocPath(containerPath, particle.id);

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

  // Suspend playback while any field inside the card has focus so typing
  // doesn't race the dwell timer or get eaten by global key handlers.
  const [editing, setEditing] = useState(false);
  useSuspendPlayback(editing, `task-edit-${particle.id}`);

  useFixedDwell({
    id: particle.id,
    durationS: DWELL_DURATION_S,
    paused,
    onEnded,
    onProgress,
  });

  const titleField = useLiveDraftField({
    remoteValue: title,
    commit: (value) =>
      updateParticleProperties<'task'>(docPath, { title: value }),
  });
  const notesField = useLiveDraftField({
    remoteValue: notes ?? '',
    commit: (value) =>
      updateParticleProperties<'task'>(docPath, { notes: value }),
  });

  // Checklist writes replace the whole array (merged against the latest live
  // value); concurrent edits to the same checklist are last-write-wins.
  const checklistRef = useRef(checklist);
  useEffect(() => {
    checklistRef.current = checklist;
  }, [checklist]);

  const writeChecklist = useCallback(
    (items: ChecklistItem[]) => {
      // Advance the local base before the write so a second edit issued before
      // the next snapshot composes on top of this one instead of dropping it.
      checklistRef.current = items;
      return updateParticleProperties<'task'>(docPath, { checklist: items });
    },
    [docPath],
  );

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

  const handleToggleItem = useCallback(
    (index: number, checked: boolean) => {
      const items = checklistRef.current.map((item, i) =>
        i === index ? { ...item, done: checked } : 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(
    (value: string) => {
      if (value === UNASSIGNED) {
        void updateParticle(docPath, 'properties.assigned_to', deleteField());
      } else {
        void updateParticleProperties<'task'>(docPath, { assigned_to: value });
      }
    },
    [docPath],
  );

  const assignee = resolveHumanDisplay(assigned_to, network?.humans);
  const doneCount = checklist.filter((item) => item.done).length;

  return (
    <div className="flex h-full w-full items-center justify-center bg-gradient-to-b from-black/40 via-black/20 to-black/40 px-8 pt-[var(--stream-safe-top,2rem)] pb-[var(--stream-safe-bottom,2rem)]">
      <div
        className="scrollbar-card flex max-h-full w-full max-w-[calc(var(--message-content-width)_+_var(--message-card-padding)*2)] flex-col gap-5 overflow-y-auto overscroll-contain rounded bg-white/10 p-[var(--message-card-padding)] backdrop-blur-md"
        onFocusCapture={() => setEditing(true)}
        onBlurCapture={(e) => {
          if (!e.currentTarget.contains(e.relatedTarget)) setEditing(false);
        }}
      >
        <div className="flex items-start gap-3">
          <Checkbox
            checked={done}
            onCheckedChange={(checked) => handleToggleDone(checked === true)}
            className="mt-1.5 size-5 rounded-full border-white/40 data-[state=checked]:border-emerald-500 data-[state=checked]:bg-emerald-500"
            aria-label={done ? 'Mark task as not done' : 'Mark task as done'}
          />
          <input
            value={titleField.value}
            onChange={(e) => titleField.onChange(e.target.value)}
            onFocus={titleField.onFocus}
            onBlur={titleField.onBlur}
            placeholder="Task title"
            className={cn(
              'w-full bg-transparent text-2xl font-semibold text-white outline-none placeholder:text-white/30',
              done && 'text-white/50 line-through',
            )}
          />
        </div>

        <Textarea
          value={notesField.value}
          onChange={(e) => notesField.onChange(e.target.value)}
          onFocus={notesField.onFocus}
          onBlur={notesField.onBlur}
          placeholder="Add notes…"
          className="min-h-16 resize-none border-none bg-transparent p-0 text-sm text-white/80 shadow-none placeholder:text-white/30 focus-visible:ring-0 dark:bg-transparent"
        />

        <div className="flex flex-col gap-1.5">
          {checklist.length > 0 && (
            <span className="text-xs text-white/40">
              {doneCount} / {checklist.length} done
            </span>
          )}
          {checklist.map((item, index) => (
            <ChecklistItemRow
              // Index keys + whole-array writes are an accepted tradeoff:
              // concurrent removal while someone types can shift focus.
              key={index}
              item={item}
              onToggle={(checked) => handleToggleItem(index, checked)}
              onCommitText={(text) => handleCommitItemText(index, text)}
              onRemove={() => handleRemoveItem(index)}
            />
          ))}
          <AddChecklistItemRow onAdd={handleAddItem} />
        </div>

        <div className="flex items-center gap-2">
          <Select
            value={assigned_to ?? UNASSIGNED}
            onValueChange={handleAssign}
          >
            <SelectTrigger
              size="sm"
              className="w-fit gap-2 border-white/15 bg-white/5 text-white/80"
            >
              {assigned_to && assignee.exists && (
                <HumanAvatar
                  size="sm"
                  initials={assignee.initials}
                  avatarObjectId={assignee.avatarObjectId}
                />
              )}
              <SelectValue placeholder="Unassigned" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value={UNASSIGNED}>Unassigned</SelectItem>
              {network?.humans?.map((human) => (
                <SelectItem key={human.id} value={human.id}>
                  {human.email_prefix}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      </div>
    </div>
  );
}

function ChecklistItemRow({
  item,
  onToggle,
  onCommitText,
  onRemove,
}: {
  item: ChecklistItem;
  onToggle: (checked: boolean) => void;
  onCommitText: (text: string) => void;
  onRemove: () => void;
}) {
  const textField = useLiveDraftField({
    remoteValue: item.text,
    commit: onCommitText,
  });

  return (
    <div className="group/item flex items-center gap-2.5">
      <Checkbox
        checked={item.done}
        onCheckedChange={(checked) => onToggle(checked === true)}
        className="border-white/30 data-[state=checked]:border-emerald-500 data-[state=checked]:bg-emerald-500"
        aria-label={
          item.done ? 'Mark subtask as not done' : 'Mark subtask as done'
        }
      />
      <input
        value={textField.value}
        onChange={(e) => textField.onChange(e.target.value)}
        onFocus={textField.onFocus}
        onBlur={textField.onBlur}
        placeholder="Subtask"
        className={cn(
          'w-full bg-transparent text-sm text-white/90 outline-none placeholder:text-white/30',
          item.done && 'text-white/40 line-through',
        )}
      />
      <button
        type="button"
        onClick={onRemove}
        className="text-white/30 opacity-0 transition-opacity hover:text-white/70 group-hover/item:opacity-100"
        aria-label="Remove subtask"
      >
        <X className="size-3.5" />
      </button>
    </div>
  );
}

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

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

  return (
    <div className="flex items-center gap-2.5">
      <Plus className="size-4 text-white/30" />
      <input
        value={draft}
        onChange={(e) => setDraft(e.target.value)}
        onKeyDown={(e) => {
          if (e.key === 'Enter') {
            e.preventDefault();
            submit();
          }
        }}
        onBlur={submit}
        placeholder="Add subtask…"
        className="w-full bg-transparent text-sm text-white/70 outline-none placeholder:text-white/30"
      />
    </div>
  );
}
