"use client";

import { useRef, useState, useEffect } from "react";
import type { ProgrammingBlock } from "@/lib/types";

const SNAP_MINS = 15;

export const BLOCK_COLORS = [
  "#3b82f6",
  "#8b5cf6",
  "#10b981",
  "#f59e0b",
  "#ef4444",
  "#06b6d4",
  "#6366f1",
  "#ec4899",
];

export function timeToMins(time: string): number {
  const [h, m] = time.split(":").map(Number);
  return h * 60 + m;
}

export function minsToTime(mins: number): string {
  const clamped = ((Math.round(mins / SNAP_MINS) * SNAP_MINS) % 1440 + 1440) % 1440;
  return `${Math.floor(clamped / 60).toString().padStart(2, "0")}:${(clamped % 60).toString().padStart(2, "0")}:00`;
}

function snap(mins: number): number {
  return Math.round(mins / SNAP_MINS) * SNAP_MINS;
}

type DragKind = "move" | "resize" | "create";

interface DragState {
  kind: DragKind;
  blockId?: string;
  startMins: number;
  offsetMins: number;
}

interface Draft {
  id: string;
  startMins: number;
  durationMins: number;
}

interface BlockTimelineProps {
  blocks: ProgrammingBlock[];
  selectedId: string | null;
  onSelect: (id: string | null) => void;
  onChange: (blocks: ProgrammingBlock[]) => void;
  onCreateBlock: (startMins: number, durationMins: number) => void;
}

export function BlockTimeline({
  blocks,
  selectedId,
  onSelect,
  onChange,
  onCreateBlock,
}: BlockTimelineProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const dragRef = useRef<DragState | null>(null);
  const blocksRef = useRef(blocks);
  blocksRef.current = blocks;

  const onChangeRef = useRef(onChange);
  onChangeRef.current = onChange;
  const onCreateRef = useRef(onCreateBlock);
  onCreateRef.current = onCreateBlock;

  const [draft, setDraft] = useState<Draft | null>(null);

  const clientXToMins = (clientX: number): number => {
    const rect = containerRef.current?.getBoundingClientRect();
    if (!rect) return 0;
    return Math.max(0, Math.min(1440, snap((clientX - rect.left) / rect.width * 1440)));
  };

  useEffect(() => {
    const handleMove = (e: MouseEvent) => {
      const drag = dragRef.current;
      if (!drag) return;
      const cur = clientXToMins(e.clientX);
      const blks = blocksRef.current;

      if (drag.kind === "move" && drag.blockId) {
        const block = blks.find((b) => b.id === drag.blockId);
        if (!block) return;
        const newStart = snap(Math.max(0, Math.min(1440 - block.duration_mins, cur - drag.offsetMins)));
        setDraft({ id: drag.blockId, startMins: newStart, durationMins: block.duration_mins });
      } else if (drag.kind === "resize" && drag.blockId) {
        const block = blks.find((b) => b.id === drag.blockId);
        if (!block) return;
        const newDuration = Math.max(SNAP_MINS, snap(cur - drag.startMins));
        setDraft({ id: drag.blockId, startMins: drag.startMins, durationMins: newDuration });
      } else if (drag.kind === "create") {
        const start = Math.min(drag.startMins, cur);
        const end = Math.max(drag.startMins, cur);
        setDraft({ id: "__new__", startMins: start, durationMins: Math.max(SNAP_MINS, end - start) });
      }
    };

    const handleUp = () => {
      const drag = dragRef.current;
      if (!drag) return;
      dragRef.current = null;

      setDraft((prev) => {
        if (!prev) return null;
        const blks = blocksRef.current;
        if (drag.kind === "move" && drag.blockId) {
          onChangeRef.current(blks.map((b) => b.id === drag.blockId ? { ...b, start_time: minsToTime(prev.startMins) } : b));
        } else if (drag.kind === "resize" && drag.blockId) {
          onChangeRef.current(blks.map((b) => b.id === drag.blockId ? { ...b, duration_mins: prev.durationMins } : b));
        } else if (drag.kind === "create" && prev.durationMins >= SNAP_MINS) {
          onCreateRef.current(prev.startMins, prev.durationMins);
        }
        return null;
      });
    };

    window.addEventListener("mousemove", handleMove);
    window.addEventListener("mouseup", handleUp);
    return () => {
      window.removeEventListener("mousemove", handleMove);
      window.removeEventListener("mouseup", handleUp);
    };
  }, []);

  return (
    <div className="select-none space-y-1">
      {/* Hour labels */}
      <div className="relative h-4">
        {[0, 3, 6, 9, 12, 15, 18, 21, 24].map((h) => (
          <span
            key={h}
            className="absolute -translate-x-1/2 text-[10px] text-zinc-600"
            style={{ left: `${(h / 24) * 100}%` }}
          >
            {h.toString().padStart(2, "0")}
          </span>
        ))}
      </div>

      {/* Timeline strip */}
      <div
        ref={containerRef}
        className="relative h-16 cursor-crosshair rounded-md border border-zinc-700 bg-zinc-900 overflow-hidden"
        onMouseDown={(e) => {
          if (e.button !== 0) return;
          const startMins = clientXToMins(e.clientX);
          dragRef.current = { kind: "create", startMins, offsetMins: 0 };
          setDraft({ id: "__new__", startMins, durationMins: SNAP_MINS });
        }}
      >
        {/* Hour grid */}
        {Array.from({ length: 25 }, (_, i) => (
          <div
            key={i}
            className={`absolute inset-y-0 w-px ${i % 6 === 0 ? "bg-zinc-700" : "bg-zinc-800"}`}
            style={{ left: `${(i / 24) * 100}%` }}
          />
        ))}

        {/* Blocks */}
        {blocks.map((block, idx) => {
          const startMins = draft?.id === block.id ? draft.startMins : timeToMins(block.start_time);
          const durationMins = draft?.id === block.id ? draft.durationMins : block.duration_mins;
          const color = BLOCK_COLORS[idx % BLOCK_COLORS.length];
          const isSelected = block.id === selectedId;

          return (
            <div
              key={block.id}
              title={`${block.name || "Untitled"} · ${minsToTime(startMins).slice(0, 5)} · ${durationMins}m`}
              className={`absolute top-1.5 bottom-1.5 rounded flex items-center overflow-hidden ${isSelected ? "ring-2 ring-white ring-offset-1 ring-offset-zinc-900" : "opacity-75 hover:opacity-100"}`}
              style={{
                left: `${(startMins / 1440) * 100}%`,
                width: `max(${(durationMins / 1440) * 100}%, 6px)`,
                backgroundColor: color,
              }}
              onMouseDown={(e) => {
                e.stopPropagation();
                onSelect(block.id);
                dragRef.current = {
                  kind: "move",
                  blockId: block.id,
                  startMins: timeToMins(block.start_time),
                  offsetMins: clientXToMins(e.clientX) - timeToMins(block.start_time),
                };
              }}
            >
              <span className="px-1.5 text-[10px] font-medium text-white truncate pointer-events-none flex-1">
                {block.name || "Untitled"}
              </span>
              {/* Resize handle */}
              <div
                className="absolute right-0 inset-y-0 w-2 cursor-ew-resize"
                onMouseDown={(e) => {
                  e.stopPropagation();
                  dragRef.current = {
                    kind: "resize",
                    blockId: block.id,
                    startMins: timeToMins(block.start_time),
                    offsetMins: 0,
                  };
                }}
              />
            </div>
          );
        })}

        {/* Create preview */}
        {draft?.id === "__new__" && (
          <div
            className="absolute top-1.5 bottom-1.5 rounded bg-zinc-400/40 border border-dashed border-zinc-400/60 pointer-events-none"
            style={{
              left: `${(draft.startMins / 1440) * 100}%`,
              width: `max(${(draft.durationMins / 1440) * 100}%, 6px)`,
            }}
          />
        )}
      </div>

      <p className="text-[10px] text-zinc-600">
        Drag to move · Drag right edge to resize · Click and drag empty space to create
      </p>
    </div>
  );
}
