import { createMemo, createSignal, For, Show } from "solid-js";
import { ArrowLeft, ArrowRight, Settings2, Trash2 } from "lucide-solid";

import Modal from "~/components/modal";
import { useApp } from "~/lib/app-context";
import { colorOptions, formatPrettyDate, getColorStyle, resolveAttachmentHref } from "~/lib/utils";

export default function BoardRoute() {
  const app = useApp();
  const workspaceSlug = () => app.primaryWorkspace()?.slug ?? "personal";
  const groups = createMemo(() =>
    [...app.state.boardGroups]
      .filter(group => group.workspaceSlug === workspaceSlug())
      .sort((left, right) => left.order - right.order),
  );
  const labels = createMemo(() => app.state.labels.filter(label => label.workspaceSlug === workspaceSlug()));
  const [selectedTaskId, setSelectedTaskId] = createSignal<string | null>(null);
  const [newTaskTitle, setNewTaskTitle] = createSignal("");
  const [newGroup, setNewGroup] = createSignal("");
  const [newGroupColor, setNewGroupColor] = createSignal("slate");
  const [newComment, setNewComment] = createSignal("");
  const [editingGroupId, setEditingGroupId] = createSignal<string | null>(null);
  const [editingGroupName, setEditingGroupName] = createSignal("");
  const [editingGroupColor, setEditingGroupColor] = createSignal("slate");
  let draggedTaskId: string | null = null;

  const selectedTask = createMemo(() =>
    app.state.tasks.find(task => task.id === selectedTaskId()),
  );

  const tasksForGroup = (groupId: string) =>
    app.state.tasks.filter(task => task.workspaceSlug === workspaceSlug() && task.boardGroupId === groupId);

  const createInboxTask = async () => {
    if (!newTaskTitle().trim()) {
      return;
    }
    const task = await app.createTask({
      workspaceSlug: workspaceSlug(),
      boardGroupId: "group-inbox",
      title: newTaskTitle(),
      color: "slate"
    });
    setSelectedTaskId(task.id);
    setNewTaskTitle("");
  };

  const addGroup = () => {
    if (!newGroup().trim()) {
      return;
    }
    app.addBoardGroup(workspaceSlug(), newGroup(), newGroupColor());
    setNewGroup("");
    setNewGroupColor("slate");
  };

  const openGroupSettings = (groupId: string) => {
    const group = groups().find(entry => entry.id === groupId);
    if (!group) {
      return;
    }
    setEditingGroupId(group.id);
    setEditingGroupName(group.name);
    setEditingGroupColor(group.color);
  };

  const saveGroupSettings = () => {
    const groupId = editingGroupId();
    if (!groupId || !editingGroupName().trim()) {
      return;
    }
    app.updateBoardGroup(groupId, {
      name: editingGroupName().trim(),
      color: editingGroupColor()
    });
    setEditingGroupId(null);
  };

  return (
    <div class="flex h-full flex-col">
      {/* Page header */}
      <div class="mb-6 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
        <div>
          <h1 class="text-xl font-semibold">Board</h1>
          <p class="mt-1 text-sm text-[var(--text-muted)]">Flexible custom groups</p>
        </div>
        <div class="flex gap-2">
          <input
            class="input-base w-64"
            placeholder="Quick capture..."
            value={newTaskTitle()}
            onInput={event => setNewTaskTitle(event.currentTarget.value)}
            onKeyDown={event => event.key === "Enter" && void createInboxTask()}
          />
          <button class="button-primary px-4 py-2 text-sm" onClick={() => void createInboxTask()}>
            Add task
          </button>
        </div>
      </div>

      {/* Board columns */}
      <div class="flex-1 overflow-hidden">
        <div class="scrollbar-thin flex h-full gap-4 overflow-x-auto pb-4">
          <For each={groups()}>
            {group => (
              <div
                class="w-72 shrink-0 rounded-lg border border-[var(--border)] bg-[var(--surface)]"
                onDragOver={event => event.preventDefault()}
                onDrop={() => draggedTaskId && app.moveTask(draggedTaskId, group.id)}
              >
                {/* Column header */}
                <div class="border-b border-[var(--border)] px-3 py-2">
                  <div class="flex items-center justify-between">
                    <div class="flex items-center gap-2">
                      <span
                        class="h-3 w-3 rounded-full"
                        style={{ background: getColorStyle(group.color).bg }}
                      />
                      <span class="text-sm font-medium">{group.name}</span>
                      <span class="text-xs text-[var(--text-muted)]">
                        {tasksForGroup(group.id).length}
                      </span>
                    </div>
                    <div class="flex items-center gap-1">
                      <button
                        class="flex h-6 w-6 items-center justify-center rounded text-[var(--text-muted)] transition-colors hover:bg-[var(--bg-subtle)] hover:text-[var(--text)] disabled:opacity-30"
                        aria-label={`Move ${group.name} left`}
                        onClick={() => app.reorderBoardGroup(group.id, -1)}
                        disabled={groups().findIndex(entry => entry.id === group.id) === 0}
                      >
                        <ArrowLeft size={14} />
                      </button>
                      <button
                        class="flex h-6 w-6 items-center justify-center rounded text-[var(--text-muted)] transition-colors hover:bg-[var(--bg-subtle)] hover:text-[var(--text)] disabled:opacity-30"
                        aria-label={`Move ${group.name} right`}
                        onClick={() => app.reorderBoardGroup(group.id, 1)}
                        disabled={groups().findIndex(entry => entry.id === group.id) === groups().length - 1}
                      >
                        <ArrowRight size={14} />
                      </button>
                      <button
                        class="flex h-6 w-6 items-center justify-center rounded text-[var(--text-muted)] transition-colors hover:bg-[var(--bg-subtle)] hover:text-[var(--text)]"
                        aria-label={`Edit ${group.name}`}
                        onClick={() => openGroupSettings(group.id)}
                      >
                        <Settings2 size={14} />
                      </button>
                    </div>
                  </div>
                </div>

                {/* Tasks */}
                <div class="max-h-[calc(100vh-220px)] space-y-2 overflow-y-auto p-2">
                  <For each={tasksForGroup(group.id)}>
                    {task => {
                      const color = getColorStyle(task.color);
                      return (
                        <button
                          draggable
                          onDragStart={() => {
                            draggedTaskId = task.id;
                          }}
                          onClick={() => setSelectedTaskId(task.id)}
                          class="w-full rounded-md border border-[var(--border)] bg-[var(--bg-subtle)] p-3 text-left transition-colors hover:border-[var(--border-strong)] hover:bg-[var(--bg-muted)]"
                        >
                          <div class="flex items-start justify-between gap-2">
                            <p class="text-sm font-medium">{task.title}</p>
                            <span
                              class="shrink-0 rounded px-1.5 py-0.5 text-xs font-medium"
                              style={{ background: color.bg, color: color.text }}
                            >
                              {task.status.replace("_", " ").slice(0, 3)}
                            </span>
                          </div>
                          <Show when={task.description}>
                            <p class="mt-1 line-clamp-2 text-xs text-[var(--text-muted)]">
                              {task.description}
                            </p>
                          </Show>
                          <Show when={task.labelIds.length > 0}>
                            <div class="mt-2 flex flex-wrap gap-1">
                              <For each={task.labelIds.slice(0, 3).map(labelId => labels().find(label => label.id === labelId)).filter(Boolean)}>
                                {label => (
                                  <span
                                    class="rounded px-1.5 py-0.5 text-xs font-medium"
                                    style={{ background: getColorStyle(label!.color).bg, color: getColorStyle(label!.color).text }}
                                  >
                                    {label!.name}
                                  </span>
                                )}
                              </For>
                            </div>
                          </Show>
                          <Show when={task.dueAt}>
                            <p class="mt-2 text-xs text-[var(--text-subtle)]">
                              {formatPrettyDate(task.dueAt)}
                            </p>
                          </Show>
                        </button>
                      );
                    }}
                  </For>
                </div>
              </div>
            )}
          </For>

          {/* Add group column */}
          <div class="w-72 shrink-0 rounded-lg border border-dashed border-[var(--border)] bg-[var(--bg-subtle)] p-3">
            <p class="mb-2 text-xs font-medium uppercase tracking-wide text-[var(--text-muted)]">Add group</p>
            <input
              class="input-base mb-2 text-sm"
              placeholder="Group name"
              value={newGroup()}
              onInput={event => setNewGroup(event.currentTarget.value)}
            />
            <select
              class="input-base mb-2 text-sm"
              value={newGroupColor()}
              onInput={event => setNewGroupColor(event.currentTarget.value)}
            >
              <For each={colorOptions}>{option => <option value={option}>{option}</option>}</For>
            </select>
            <button
              class="button-secondary w-full px-3 py-1.5 text-sm"
              onClick={() => addGroup()}
            >
              Add group
            </button>
          </div>
        </div>
      </div>

      {/* Labels footer */}
      <div class="mt-4 rounded-lg border border-[var(--border)] bg-[var(--surface)] px-4 py-3">
        <div class="flex items-center gap-3">
          <span class="text-xs font-medium uppercase tracking-wide text-[var(--text-muted)]">Labels</span>
          <div class="flex flex-wrap gap-2">
            <For each={labels()}>
              {label => (
                <span
                  class="rounded px-2 py-0.5 text-xs font-medium"
                  style={{ background: getColorStyle(label.color).bg, color: getColorStyle(label.color).text }}
                >
                  {label.name}
                </span>
              )}
            </For>
          </div>
        </div>
      </div>

      {/* Edit group modal */}
      <Modal open={Boolean(editingGroupId())} title="Edit group" onClose={() => setEditingGroupId(null)}>
        <div class="space-y-4">
          <div>
            <label class="mb-1.5 block text-sm font-medium">Name</label>
            <input
              class="input-base"
              value={editingGroupName()}
              onInput={event => setEditingGroupName(event.currentTarget.value)}
            />
          </div>
          <div>
            <label class="mb-1.5 block text-sm font-medium">Color</label>
            <select
              class="input-base"
              value={editingGroupColor()}
              onInput={event => setEditingGroupColor(event.currentTarget.value)}
            >
              <For each={colorOptions}>{option => <option value={option}>{option}</option>}</For>
            </select>
          </div>
          <button class="button-primary w-full px-4 py-2 text-sm" onClick={saveGroupSettings}>
            Save changes
          </button>
        </div>
      </Modal>

      {/* Task detail modal */}
      <Modal open={Boolean(selectedTask())} title={selectedTask()?.title ?? "Task"} onClose={() => setSelectedTaskId(null)}>
        <Show when={selectedTask()}>
          {task => (
            <div class="space-y-4">
              <div>
                <label class="mb-1.5 block text-sm font-medium">Title</label>
                <input
                  class="input-base"
                  value={task().title}
                  onInput={event => app.updateTask(task().id, current => {
                    current.title = event.currentTarget.value;
                  })}
                />
              </div>

              <div>
                <label class="mb-1.5 block text-sm font-medium">Description</label>
                <textarea
                  class="input-base min-h-24 resize-none"
                  value={task().description}
                  onInput={event => app.updateTask(task().id, current => {
                    current.description = event.currentTarget.value;
                  })}
                />
              </div>

              <div class="grid gap-4 sm:grid-cols-2">
                <div>
                  <label class="mb-1.5 block text-sm font-medium">Due date</label>
                  <input
                    class="input-base"
                    type="datetime-local"
                    value={task().dueAt?.slice(0, 16) ?? ""}
                    onInput={event => app.updateTask(task().id, current => {
                      current.dueAt = event.currentTarget.value ? new Date(event.currentTarget.value).toISOString() : undefined;
                    })}
                  />
                </div>
                <div>
                  <label class="mb-1.5 block text-sm font-medium">Color</label>
                  <select
                    class="input-base"
                    value={task().color}
                    onInput={event => app.updateTask(task().id, current => {
                      current.color = event.currentTarget.value;
                    })}
                  >
                    <For each={colorOptions}>
                      {option => <option value={option}>{option}</option>}
                    </For>
                  </select>
                </div>
              </div>

              {/* Labels */}
              <div>
                <p class="mb-2 text-sm font-medium">Labels</p>
                <div class="flex flex-wrap gap-2">
                  <For each={labels()}>
                    {label => {
                      const active = () => task().labelIds.includes(label.id);
                      return (
                        <button
                          class="rounded px-2 py-1 text-xs font-medium transition-colors"
                          classList={{
                            "bg-[var(--bg-muted)]": !active()
                          }}
                          style={{
                            background: active() ? getColorStyle(label.color).bg : undefined,
                            color: active() ? getColorStyle(label.color).text : "var(--text-muted)"
                          }}
                          onClick={() =>
                            app.updateTask(task().id, current => {
                              current.labelIds = active()
                                ? current.labelIds.filter(labelId => labelId !== label.id)
                                : [...current.labelIds, label.id];
                            })
                          }
                        >
                          {label.name}
                        </button>
                      );
                    }}
                  </For>
                </div>
              </div>

              {/* Attachments */}
              <div>
                <label class="mb-1.5 block text-sm font-medium">Attachments</label>
                <input
                  class="input-base"
                  type="file"
                  multiple
                  onChange={event => app.attachFilesToTask(task().id, event.currentTarget.files)}
                />
                <Show when={task().attachments.length > 0}>
                  <div class="mt-2 space-y-1">
                    <For each={task().attachments}>
                      {attachment => (
                        <div class="flex items-center justify-between gap-2 rounded-md bg-[var(--bg-subtle)] px-3 py-2 text-sm">
                          <a
                            class="min-w-0 flex-1 truncate"
                            href={resolveAttachmentHref(attachment.dataUrl)}
                            download={attachment.name}
                          >
                            {attachment.name}
                          </a>
                          <span class="text-xs text-[var(--text-muted)]">
                            {Math.round(attachment.size / 1024)} KB
                          </span>
                          <button
                            class="flex h-6 w-6 items-center justify-center rounded text-[var(--text-muted)] transition-colors hover:bg-[var(--bg-muted)] hover:text-[var(--error)]"
                            aria-label={`Remove ${attachment.name}`}
                            onClick={() => void app.removeTaskAttachment(task().id, attachment.id)}
                          >
                            <Trash2 size={14} />
                          </button>
                        </div>
                      )}
                    </For>
                  </div>
                </Show>
              </div>

              {/* Comments */}
              <div>
                <p class="mb-2 text-sm font-medium">Comments</p>
                <div class="mb-2 space-y-2">
                  <For each={task().comments}>
                    {comment => (
                      <div class="rounded-md bg-[var(--bg-subtle)] px-3 py-2">
                        <p class="text-xs font-medium">{comment.author}</p>
                        <p class="mt-1 text-sm text-[var(--text-muted)]">{comment.content}</p>
                      </div>
                    )}
                  </For>
                </div>
                <div class="flex gap-2">
                  <input
                    class="input-base flex-1"
                    placeholder="Add a comment..."
                    value={newComment()}
                    onInput={event => setNewComment(event.currentTarget.value)}
                    onKeyDown={event => {
                      if (event.key === "Enter" && newComment().trim()) {
                        app.createTaskComment(task().id, newComment());
                        setNewComment("");
                      }
                    }}
                  />
                  <button
                    class="button-secondary px-3 py-2 text-sm"
                    onClick={() => {
                      if (newComment().trim()) {
                        app.createTaskComment(task().id, newComment());
                        setNewComment("");
                      }
                    }}
                  >
                    Send
                  </button>
                </div>
              </div>
            </div>
          )}
        </Show>
      </Modal>
    </div>
  );
}
