import { useEffect, useState } from "preact/hooks";
import { cardDragType, readCardDrag } from "../drag";
import type { Card, ListWithCards } from "../types";
import { CardItem } from "./CardItem";
import { ConfirmDialog } from "./ConfirmDialog";

interface ListColumnProps {
  list: ListWithCards;
  managingLists: boolean;
  onEditList: (patch: { name?: string; position?: number }) => Promise<void>;
  onDeleteList: () => Promise<void>;
  onCreateCard: (title: string) => Promise<void>;
  onEditCard: (cardID: number, patch: { title?: string; description?: string; done?: boolean }) => Promise<void>;
  onMoveCard: (cardID: number, sourceListID: number, targetListID: number, index: number) => Promise<void>;
  onOpenCard: (id: number) => void;
}

interface DropZoneProps {
  index: number;
  onDropCard: (cardID: number, sourceListID: number, index: number) => Promise<void>;
}

function DropZone({ index, onDropCard }: DropZoneProps) {
  const [active, setActive] = useState(false);
  return (
    <div
      class={"drop-zone " + (active ? "is-active" : "")}
      aria-label="Drop card here"
      onDragOver={(event) => {
        if (event.dataTransfer?.types.includes(cardDragType)) {
          event.preventDefault();
          event.dataTransfer.dropEffect = "move";
          setActive(true);
        }
      }}
      onDragLeave={() => setActive(false)}
      onDrop={(event) => {
        event.preventDefault();
        setActive(false);
        const payload = readCardDrag(event as unknown as DragEvent);
        if (payload) void onDropCard(payload.cardID, payload.sourceListID, index);
      }}
    />
  );
}

export function ListColumn({
  list,
  onEditList,
  onDeleteList,
  onCreateCard,
  onEditCard,
  onMoveCard,
  onOpenCard,
  managingLists
}: ListColumnProps) {
  const [editingName, setEditingName] = useState(false);
  const [name, setName] = useState(list.name);
  const [addingCard, setAddingCard] = useState(false);
  const [cardTitle, setCardTitle] = useState("");
  const [confirming, setConfirming] = useState(false);
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    if (!managingLists && editingName) {
      setName(list.name);
      setEditingName(false);
    } else if (!editingName) {
      setName(list.name);
    }
  }, [editingName, list.name, managingLists]);

  const saveName = async () => {
    if (!name.trim() || name.trim() === list.name) {
      setName(list.name);
      setEditingName(false);
      return;
    }
    setSaving(true);
    try {
      await onEditList({ name });
      setEditingName(false);
    } catch {
      setName(list.name);
    } finally {
      setSaving(false);
    }
  };

  const addCard = async () => {
    if (!cardTitle.trim()) return;
    setSaving(true);
    try {
      await onCreateCard(cardTitle);
      setCardTitle("");
      setAddingCard(false);
    } catch {
      // App has shown an error toast.
    } finally {
      setSaving(false);
    }
  };

  const remove = async () => {
    setConfirming(false);
    try {
      await onDeleteList();
    } catch {
      // App has shown an error toast.
    }
  };

  return (
    <>
      <section class={"list-column " + (managingLists ? "is-managing" : "")}>
        <div class="list-header">
          <div class="list-heading">
            {editingName ? (
              <input
                value={name}
                maxlength={120}
                autoFocus
                aria-label="List name"
                onInput={(event) => setName(event.currentTarget.value)}
                onKeyDown={(event) => {
                  if (event.key === "Enter") void saveName();
                  if (event.key === "Escape") {
                    setName(list.name);
                    setEditingName(false);
                  }
                }}
                onBlur={() => void saveName()}
              />
            ) : managingLists ? (
              <button type="button" class="list-name" onClick={() => setEditingName(true)}>{list.name}</button>
            ) : (
              <h2 class="list-name-text">{list.name}</h2>
            )}
            <span class="count-badge">{list.cards.length}</span>
          </div>
          {managingLists ? <button
            type="button"
            class="icon-button list-delete"
            aria-label={"Delete " + list.name}
            title="Delete list"
            onClick={() => setConfirming(true)}
          >
            ×
          </button> : null}
        </div>
        <div class="cards-stack">
          <DropZone index={0} onDropCard={(cardID, sourceListID, index) => onMoveCard(cardID, sourceListID, list.id, index)} />
          {list.cards.map((card: Card, index) => (
            <div class="card-slot" key={card.id}>
              <CardItem
                card={card}
                onEdit={(patch) => onEditCard(card.id, patch)}
                onOpen={() => onOpenCard(card.id)}
              />
              <DropZone index={index + 1} onDropCard={(cardID, sourceListID, dropIndex) => onMoveCard(cardID, sourceListID, list.id, dropIndex)} />
            </div>
          ))}
          {!list.cards.length ? <p class="list-empty">No cards yet. Drop one here or add the first task.</p> : null}
        </div>
        {addingCard ? (
          <form
            class="quick-add"
            onSubmit={(event) => {
              event.preventDefault();
              void addCard();
            }}
          >
            <input
              value={cardTitle}
              maxlength={240}
              autoFocus
              placeholder="What needs doing?"
              aria-label="New card title"
              onInput={(event) => setCardTitle(event.currentTarget.value)}
              onKeyDown={(event) => {
                if (event.key === "Escape") {
                  setAddingCard(false);
                  setCardTitle("");
                }
              }}
            />
            <div class="quick-add-actions">
              <button type="submit" class="button button-primary" disabled={saving}>Add card</button>
              <button type="button" class="button button-quiet" disabled={saving} onClick={() => setAddingCard(false)}>Cancel</button>
            </div>
          </form>
        ) : (
          <button type="button" class="add-card-button" onClick={() => setAddingCard(true)}>
            <span aria-hidden="true">＋</span> Add a card
          </button>
        )}
      </section>
      <ConfirmDialog
        open={confirming}
        title={"Delete “" + list.name + "”? "}
        detail="All cards in this list will be permanently removed."
        confirmLabel="Delete list"
        onCancel={() => setConfirming(false)}
        onConfirm={() => void remove()}
      />
    </>
  );
}
