"use client";

import { useRef, RefObject } from "react";
import { useDroppable } from "@dnd-kit/core";
import {
  format,
  differenceInDays,
  startOfDay,
  isToday,
  isWeekend,
  isBefore,
  parseISO,
  addDays,
} from "date-fns";
import { cn } from "@/lib/utils";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { getInitials } from "@/lib/utils";
import { ScheduleTaskBlock } from "./ScheduleTaskBlock";
import {
  ScheduleTask,
  ScheduleArtist,
  DAY_WIDTH,
  ROW_HEIGHT,
  HEADER_HEIGHT,
} from "@/app/(dashboard)/schedule/SchedulePageClient";
import { AlertTriangle } from "lucide-react";

interface ResizePreview {
  taskId: string;
  endDate: Date;
  estimatedHours: number;
}

interface ScheduleTimelineProps {
  artists: ScheduleArtist[];
  tasks: ScheduleTask[];
  days: Date[];
  viewStart: Date;
  canEdit: boolean;
  timelineRef: RefObject<HTMLDivElement | null>;
  resizePreview: ResizePreview | null;
  onResizeMouseDown: (
    taskId: string,
    currentEndDate: string
  ) => (e: React.MouseEvent) => void;
  activeDragId: string | null;
  onUnschedule: (taskId: string) => void;
  dayWidth: number;
  rowHeight: number;
}

function toDate(val: string | null | undefined): Date | null {
  if (!val) return null;
  try {
    return parseISO(val);
  } catch {
    return new Date(val);
  }
}

function getDayIndex(date: Date | null, viewStart: Date): number {
  if (!date) return -1;
  return differenceInDays(date, viewStart);
}

/** Greedy lane assignment based on hour-ranges so task width = hours.
 *  Two tasks for the same artist conflict when their [startHour, endHour]
 *  ranges overlap. Each task occupies exactly one lane (fixed height).
 */
function computeLanes(
  tasks: ScheduleTask[],
  viewStart: Date
): Map<string, number> {
  // Build hour ranges: startHour = dayIndex * 8, endHour = startHour + estimatedHours
  const ranges = tasks
    .filter((t) => t.scheduledStartDate)
    .map((t) => {
      const dayIdx = Math.max(
        0,
        differenceInDays(toDate(t.scheduledStartDate)!, viewStart)
      );
      const startHour = dayIdx * 8;
      const endHour = startHour + (t.estimatedHours ?? 8);
      return { id: t.id, startHour, endHour };
    })
    .sort((a, b) => a.startHour - b.startHour);

  const laneEndHours: number[] = [];
  const result = new Map<string, number>();

  for (const task of ranges) {
    let lane = laneEndHours.findIndex((end) => task.startHour >= end);
    if (lane === -1) lane = laneEndHours.length;
    laneEndHours[lane] = task.endHour;
    result.set(task.id, lane);
  }

  return result;
}

function getTaskDuration(task: ScheduleTask): number {
  return Math.max(1, Math.ceil((task.estimatedHours ?? 8) / 8));
}

// Calculate daily load (hours) for each artist
function calcDailyLoad(
  tasks: ScheduleTask[],
  artistId: string,
  days: Date[]
): Record<string, number> {
  const result: Record<string, number> = {};
  const artistTasks = tasks.filter((t) => t.assignedArtistId === artistId);

  for (const day of days) {
    const dayStr = format(day, "yyyy-MM-dd");
    let totalHours = 0;
    for (const task of artistTasks) {
      const start = toDate(task.scheduledStartDate);
      const end = toDate(task.scheduledEndDate) ?? start;
      if (!start || !end) continue;
      const dayStart = new Date(day);
      dayStart.setHours(0, 0, 0, 0);
      const dayEnd = new Date(day);
      dayEnd.setHours(23, 59, 59, 999);

      if (start <= dayEnd && end >= dayStart) {
        const dur = Math.max(1, differenceInDays(end, start) + 1);
        const hoursPerDay = (task.estimatedHours ?? 8) / dur;
        totalHours += hoursPerDay;
      }
    }
    result[dayStr] = totalHours;
  }
  return result;
}

function ArtistLabel({
  artist,
  isOverloaded,
  rowHeight,
}: {
  artist: ScheduleArtist;
  isOverloaded: boolean;
  rowHeight: number;
}) {
  return (
    <div
      className="flex items-center gap-2.5 px-3 border-b border-zinc-800 bg-zinc-900"
      style={{ height: rowHeight }}
    >
      <Avatar className="h-7 w-7 shrink-0">
        <AvatarImage src={artist.image ?? undefined} />
        <AvatarFallback className="text-[10px] bg-zinc-700 text-zinc-300">
          {getInitials(artist.name ?? artist.email)}
        </AvatarFallback>
      </Avatar>
      <div className="flex-1 min-w-0">
        <div className="flex items-center gap-1.5">
          <span className="text-xs font-medium text-zinc-200 truncate">
            {artist.name ?? artist.email.split("@")[0]}
          </span>
          {isOverloaded && (
            <AlertTriangle className="h-3 w-3 text-orange-400 shrink-0" />
          )}
        </div>
        <span className="text-[10px] text-zinc-500 capitalize">
          {artist.role.toLowerCase()}
        </span>
      </div>
    </div>
  );
}

function TimelineDropZone({ id }: { id: string }) {
  const { setNodeRef, isOver } = useDroppable({ id });
  return (
    <div
      ref={setNodeRef}
      className={cn(
        "absolute inset-0 transition-colors pointer-events-none",
        isOver && "bg-amber-500/5"
      )}
    />
  );
}

export function ScheduleTimeline({
  artists,
  tasks,
  days,
  viewStart,
  canEdit,
  timelineRef,
  resizePreview,
  onResizeMouseDown,
  activeDragId,
  onUnschedule,
  dayWidth,
  rowHeight,
}: ScheduleTimelineProps) {
  const totalWidth = days.length * dayWidth;

  return (
    <div className="flex flex-1 overflow-hidden">
      {/* Sticky left: artist labels */}
      <div
        className="flex-shrink-0 bg-zinc-900 border-r border-zinc-800 z-10"
        style={{ width: 208 }}
      >
        {/* Header spacer */}
        <div
          className="border-b border-zinc-800 bg-zinc-900"
          style={{ height: HEADER_HEIGHT }}
        />
        {artists.map((artist) => {
          const dailyLoad = calcDailyLoad(tasks, artist.id, days);
          const maxLoad = Math.max(...Object.values(dailyLoad), 0);
          const isOverloaded = maxLoad > 8;
          return (
            <ArtistLabel
              key={artist.id}
              artist={artist}
              isOverloaded={isOverloaded}
              rowHeight={rowHeight}
            />
          );
        })}
      </div>

      {/* Scrollable timeline */}
      <div
        ref={timelineRef}
        className="flex-1 overflow-x-auto overflow-y-hidden relative"
        style={{ scrollbarColor: "#3f3f46 transparent" }}
      >
        {/* Date header - sticky top */}
        <div
          className="flex sticky top-0 z-20 bg-zinc-900 border-b border-zinc-800"
          style={{ width: totalWidth, height: HEADER_HEIGHT }}
        >
          {days.map((day, i) => {
            const isT = isToday(day);
            const isWE = isWeekend(day);
            return (
              <div
                key={i}
                className={cn(
                  "flex flex-col items-center justify-center border-r text-center shrink-0 select-none",
                  isWE ? "border-zinc-800" : "border-zinc-800/60",
                  isT ? "bg-amber-500/10" : isWE ? "bg-zinc-900/80" : ""
                )}
                style={{ width: dayWidth }}
              >
                <span
                  className={cn(
                    "text-[9px] font-medium uppercase tracking-wider",
                    isT ? "text-amber-400" : "text-zinc-600"
                  )}
                >
                  {format(day, "EEE")}
                </span>
                <span
                  className={cn(
                    "text-xs font-semibold",
                    isT ? "text-amber-300" : isWE ? "text-zinc-600" : "text-zinc-400"
                  )}
                >
                  {format(day, "d")}
                </span>
                {format(day, "d") === "1" || i === 0 ? (
                  <span className="text-[9px] text-zinc-600 absolute bottom-0.5">
                    {format(day, "MMM")}
                  </span>
                ) : null}
              </div>
            );
          })}
        </div>

        {/* Artist rows */}
        <div style={{ width: totalWidth }}>
          {artists.map((artist, artistIndex) => {
            const artistTasks = tasks.filter(
              (t) => t.assignedArtistId === artist.id
            );
            const dailyLoad = calcDailyLoad(tasks, artist.id, days);

            // Apply resize preview so width animates live
            const tasksWithPreview = artistTasks.map((t) =>
              resizePreview?.taskId === t.id
                ? {
                    ...t,
                    scheduledEndDate: resizePreview.endDate.toISOString(),
                    estimatedHours: resizePreview.estimatedHours,
                  }
                : t
            );

            return (
              <div
                key={artist.id}
                className="relative border-b border-zinc-800/60"
                style={{ height: rowHeight }}
              >
                {/* Drop zone overlay */}
                <TimelineDropZone id={`timeline-row-${artist.id}`} />

                {/* Day grid lines + overload indicators */}
                {days.map((day, dayIndex) => {
                  const dayStr = format(day, "yyyy-MM-dd");
                  const load = dailyLoad[dayStr] ?? 0;
                  const isT = isToday(day);
                  const isWE = isWeekend(day);
                  const isOverloaded = load > 8;

                  return (
                    <div
                      key={dayIndex}
                      className={cn(
                        "absolute top-0 bottom-0 border-r",
                        isWE ? "border-zinc-800 bg-zinc-900/30" : "border-zinc-800/40",
                        isT && "bg-amber-500/5",
                        isOverloaded && "bg-orange-500/10"
                      )}
                      style={{
                        left: dayIndex * dayWidth,
                        width: dayWidth,
                      }}
                    />
                  );
                })}

                {/* Task blocks */}
                {tasksWithPreview.map((task) => {
                  const startDate = toDate(task.scheduledStartDate);
                  if (!startDate) return null;

                  // dayIndex may be fractional: integer part = day column,
                  // fractional part = intra-day hour offset stored in the time component.
                  const dayIdx = getDayIndex(startOfDay(startDate), viewStart);
                  const hourOffset = startDate.getHours(); // hours into the 8h workday
                  const dayIndex = dayIdx + hourOffset / 8;
                  const duration = getTaskDuration(task);

                  // Skip tasks outside view
                  if (dayIndex + duration < 0 || dayIndex >= days.length)
                    return null;

                  const taskHeight = rowHeight - 8;
                  const laneTop = 4;

                  return (
                    <ScheduleTaskBlock
                      key={task.id}
                      task={task}
                      dayIndex={dayIndex}
                      duration={duration}
                      artistIndex={artistIndex}
                      viewStart={viewStart}
                      days={days}
                      canEdit={canEdit}
                      isDragging={activeDragId === task.id}
                      onResizeMouseDown={onResizeMouseDown}
                      laneTop={laneTop}
                      taskHeight={taskHeight}
                      onUnschedule={onUnschedule}
                      dayWidth={dayWidth}
                    />
                  );
                })}
              </div>
            );
          })}

          {/* Empty state */}
          {artists.length === 0 && (
            <div className="flex items-center justify-center py-16 text-zinc-600 text-sm">
              No artists to display
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
