"use client";

import type { GanttTask, GanttChartProps, TimelineRange, GanttBarPosition } from "./types";
import { TaskStatus } from "@mosaic/shared";
import { formatDate, isPastTarget, isApproachingTarget } from "@/lib/utils/date-format";
import { useMemo, useCallback } from "react";
import styles from "./gantt.module.css";

/**
 * Represents a dependency line between two tasks
 */
interface DependencyLine {
  fromTaskId: string;
  toTaskId: string;
  fromX: number;
  fromY: number;
  toX: number;
  toY: number;
}

/**
 * Calculate the timeline range from a list of tasks
 */
function calculateTimelineRange(tasks: GanttTask[]): TimelineRange {
  if (tasks.length === 0) {
    const now = new Date();
    const oneMonthLater = new Date(now);
    oneMonthLater.setMonth(oneMonthLater.getMonth() + 1);
    
    return {
      start: now,
      end: oneMonthLater,
      totalDays: 30,
    };
  }

  let earliest = tasks[0].startDate;
  let latest = tasks[0].endDate;

  tasks.forEach((task) => {
    if (task.startDate < earliest) {
      earliest = task.startDate;
    }
    if (task.endDate > latest) {
      latest = task.endDate;
    }
  });

  // Add padding (5% on each side)
  const totalMs = latest.getTime() - earliest.getTime();
  const padding = totalMs * 0.05;
  
  const start = new Date(earliest.getTime() - padding);
  const end = new Date(latest.getTime() + padding);
  
  const totalDays = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));

  return { start, end, totalDays };
}

/**
 * Calculate the position and width for a task bar
 */
function calculateBarPosition(
  task: GanttTask,
  timelineRange: TimelineRange,
  rowIndex: number
): GanttBarPosition {
  const { start: rangeStart, totalDays } = timelineRange;
  
  const taskStartOffset = Math.max(
    0,
    (task.startDate.getTime() - rangeStart.getTime()) / (1000 * 60 * 60 * 24)
  );
  
  const taskDuration = Math.max(
    0.5, // Minimum 0.5 day width for visibility
    (task.endDate.getTime() - task.startDate.getTime()) / (1000 * 60 * 60 * 24)
  );
  
  const leftPercent = (taskStartOffset / totalDays) * 100;
  const widthPercent = (taskDuration / totalDays) * 100;

  return {
    left: `${leftPercent}%`,
    width: `${widthPercent}%`,
    top: rowIndex * 48, // 48px row height
  };
}

/**
 * Get CSS class for task status
 */
function getStatusClass(status: TaskStatus): string {
  switch (status) {
    case TaskStatus.COMPLETED:
      return "bg-green-500";
    case TaskStatus.IN_PROGRESS:
      return "bg-blue-500";
    case TaskStatus.PAUSED:
      return "bg-yellow-500";
    case TaskStatus.ARCHIVED:
      return "bg-gray-400";
    default:
      return "bg-gray-500";
  }
}

/**
 * Get CSS class for task row status
 */
function getRowStatusClass(status: TaskStatus): string {
  switch (status) {
    case TaskStatus.COMPLETED:
      return styles.rowCompleted;
    case TaskStatus.IN_PROGRESS:
      return styles.rowInProgress;
    case TaskStatus.PAUSED:
      return styles.rowPaused;
    default:
      return "";
  }
}

/**
 * Generate month labels for the timeline header
 */
function generateTimelineLabels(range: TimelineRange): Array<{ label: string; position: number }> {
  const labels: Array<{ label: string; position: number }> = [];
  const current = new Date(range.start);
  
  // Generate labels for each month in the range
  while (current <= range.end) {
    const position =
      ((current.getTime() - range.start.getTime()) / (1000 * 60 * 60 * 24)) / range.totalDays;
    
    const label = current.toLocaleDateString("en-US", {
      month: "short",
      year: "numeric",
    });
    
    labels.push({ label, position: position * 100 });
    
    // Move to next month
    current.setMonth(current.getMonth() + 1);
  }
  
  return labels;
}

/**
 * Calculate dependency lines between tasks
 */
function calculateDependencyLines(
  tasks: GanttTask[],
  timelineRange: TimelineRange
): DependencyLine[] {
  const lines: DependencyLine[] = [];
  const taskIndexMap = new Map<string, number>();
  
  // Build index map
  tasks.forEach((task, index) => {
    taskIndexMap.set(task.id, index);
  });
  
  const { start: rangeStart, totalDays } = timelineRange;
  
  tasks.forEach((task, toIndex) => {
    if (!task.dependencies || task.dependencies.length === 0) {
      return;
    }
    
    task.dependencies.forEach((depId) => {
      const fromIndex = taskIndexMap.get(depId);
      if (fromIndex === undefined) {
        return;
      }
      
      const fromTask = tasks[fromIndex];
      
      // Calculate positions (as percentages)
      const fromEndOffset = Math.max(
        0,
        (fromTask.endDate.getTime() - rangeStart.getTime()) / (1000 * 60 * 60 * 24)
      );
      const toStartOffset = Math.max(
        0,
        (task.startDate.getTime() - rangeStart.getTime()) / (1000 * 60 * 60 * 24)
      );
      
      const fromX = (fromEndOffset / totalDays) * 100;
      const toX = (toStartOffset / totalDays) * 100;
      const fromY = fromIndex * 48 + 24; // Center of the row
      const toY = toIndex * 48 + 24;
      
      lines.push({
        fromTaskId: depId,
        toTaskId: task.id,
        fromX,
        fromY,
        toX,
        toY,
      });
    });
  });
  
  return lines;
}

/**
 * Main Gantt Chart Component
 */
export function GanttChart({
  tasks,
  onTaskClick,
  height = 400,
  showDependencies = false,
}: GanttChartProps): JSX.Element {
  // Sort tasks by start date
  const sortedTasks = useMemo(() => {
    return [...tasks].sort((a, b) => a.startDate.getTime() - b.startDate.getTime());
  }, [tasks]);

  // Calculate timeline range
  const timelineRange = useMemo(() => calculateTimelineRange(sortedTasks), [sortedTasks]);

  // Generate timeline labels
  const timelineLabels = useMemo(() => generateTimelineLabels(timelineRange), [timelineRange]);

  // Calculate dependency lines
  const dependencyLines = useMemo(
    () => (showDependencies ? calculateDependencyLines(sortedTasks, timelineRange) : []),
    [showDependencies, sortedTasks, timelineRange]
  );

  const handleTaskClick = useCallback(
    (task: GanttTask) => (): void => {
      if (onTaskClick) {
        onTaskClick(task);
      }
    },
    [onTaskClick]
  );

  const handleKeyDown = useCallback(
    (task: GanttTask) => (e: React.KeyboardEvent<HTMLDivElement>): void => {
      if (e.key === "Enter" || e.key === " ") {
        e.preventDefault();
        if (onTaskClick) {
          onTaskClick(task);
        }
      }
    },
    [onTaskClick]
  );

  return (
    <div
      role="region"
      aria-label="Gantt Chart"
      className="gantt-chart bg-white rounded-lg border border-gray-200 overflow-hidden"
      style={{ height: `${height}px` }}
    >
      <div className="gantt-container flex h-full">
        {/* Task list column */}
        <div className="gantt-task-list w-64 border-r border-gray-200 overflow-y-auto flex-shrink-0">
          <div className="gantt-task-list-header bg-gray-50 p-3 border-b border-gray-200 font-semibold sticky top-0 z-10">
            Tasks
          </div>
          <div className="gantt-task-list-body">
            {sortedTasks.map((task, index) => {
              const isPast = isPastTarget(task.endDate);
              const isApproaching = !isPast && isApproachingTarget(task.endDate);
              
              return (
                <div
                  key={task.id}
                  role="row"
                  className={`gantt-task-row p-3 border-b border-gray-100 h-12 flex items-center ${getRowStatusClass(
                    task.status
                  )}`}
                >
                  <div className="flex-1 min-w-0">
                    <div className="text-sm font-medium text-gray-900 truncate">
                      {task.title}
                    </div>
                    {isPast && task.status !== TaskStatus.COMPLETED && (
                      <div className="text-xs text-amber-600">Target passed</div>
                    )}
                    {isApproaching && task.status !== TaskStatus.COMPLETED && (
                      <div className="text-xs text-orange-600">Approaching target</div>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        </div>

        {/* Timeline column */}
        <div className="gantt-timeline flex-1 overflow-x-auto overflow-y-auto">
          <div role="region" aria-label="Timeline" className="gantt-timeline-container min-w-full">
            {/* Timeline header */}
            <div className="gantt-timeline-header bg-gray-50 border-b border-gray-200 h-12 sticky top-0 z-10 relative">
              {timelineLabels.map((label, index) => (
                <div
                  key={index}
                  className="absolute top-0 bottom-0 flex items-center text-xs text-gray-600 px-2"
                  style={{ left: `${label.position}%` }}
                >
                  {label.label}
                </div>
              ))}
            </div>

            {/* Timeline grid and bars */}
            <div className="gantt-timeline-body relative">
              {/* Grid lines */}
              <div className="gantt-grid absolute inset-0 pointer-events-none">
                {timelineLabels.map((label, index) => (
                  <div
                    key={index}
                    className="absolute top-0 bottom-0 w-px bg-gray-200"
                    style={{ left: `${label.position}%` }}
                  />
                ))}
              </div>

              {/* Dependency lines SVG */}
              {showDependencies && dependencyLines.length > 0 && (
                <svg
                  className="gantt-dependencies absolute inset-0 pointer-events-none overflow-visible"
                  style={{ width: "100%", height: `${sortedTasks.length * 48}px` }}
                  aria-hidden="true"
                >
                  <defs>
                    <marker
                      id="arrowhead"
                      markerWidth="10"
                      markerHeight="7"
                      refX="9"
                      refY="3.5"
                      orient="auto"
                    >
                      <polygon points="0 0, 10 3.5, 0 7" fill="#6b7280" />
                    </marker>
                  </defs>
                  {dependencyLines.map((line) => (
                    <path
                      key={`dep-${line.fromTaskId}-${line.toTaskId}`}
                      d={`M ${line.fromX}% ${line.fromY} C ${line.fromX + 2}% ${line.fromY}, ${line.toX - 2}% ${line.toY}, ${line.toX}% ${line.toY}`}
                      stroke="#6b7280"
                      strokeWidth="2"
                      fill="none"
                      markerEnd="url(#arrowhead)"
                      className="dependency-line"
                    />
                  ))}
                </svg>
              )}

              {/* Task bars and milestones */}
              {sortedTasks.map((task, index) => {
                const position = calculateBarPosition(task, timelineRange, index);
                const statusClass = getStatusClass(task.status);
                
                // Render milestone as diamond shape
                if (task.isMilestone === true) {
                  return (
                    <div
                      key={task.id}
                      role="button"
                      tabIndex={0}
                      aria-label={`Milestone: ${task.title}, on ${formatDate(task.startDate)}`}
                      className="gantt-milestone absolute cursor-pointer transition-all hover:opacity-80 focus:outline-none focus:ring-2 focus:ring-blue-500"
                      style={{
                        left: position.left,
                        top: `${position.top + 8}px`,
                      }}
                      onClick={handleTaskClick(task)}
                      onKeyDown={handleKeyDown(task)}
                    >
                      <div
                        className={`w-6 h-6 transform rotate-45 ${statusClass}`}
                        title={task.title}
                      />
                    </div>
                  );
                }
                
                return (
                  <div
                    key={task.id}
                    role="button"
                    tabIndex={0}
                    aria-label={`Gantt bar for ${task.title}, from ${formatDate(
                      task.startDate
                    )} to ${formatDate(task.endDate)}`}
                    className={`gantt-bar absolute h-8 rounded cursor-pointer transition-all hover:opacity-80 focus:outline-none focus:ring-2 focus:ring-blue-500 ${statusClass}`}
                    style={{
                      left: position.left,
                      width: position.width,
                      top: `${position.top + 8}px`, // Center in row
                    }}
                    onClick={handleTaskClick(task)}
                    onKeyDown={handleKeyDown(task)}
                  >
                    <div className="px-2 text-xs text-white truncate leading-8">
                      {task.title}
                    </div>
                  </div>
                );
              })}

              {/* Spacer for scrolling */}
              <div
                style={{
                  height: `${sortedTasks.length * 48}px`,
                }}
              />
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
