import { describe, it, expect } from "vitest";
import { toGanttTask, toGanttTasks } from "./types";
import { TaskStatus, TaskPriority, type Task } from "@mosaic/shared";

describe("Gantt Types Helpers", (): void => {
  const baseDate = new Date("2026-02-01T00:00:00Z");

  const createTask = (overrides: Partial<Task> = {}): Task => ({
    id: "task-1",
    workspaceId: "workspace-1",
    title: "Sample Task",
    description: null,
    status: TaskStatus.NOT_STARTED,
    priority: TaskPriority.MEDIUM,
    dueDate: new Date("2026-02-15T00:00:00Z"),
    assigneeId: null,
    creatorId: "user-1",
    projectId: null,
    parentId: null,
    sortOrder: 0,
    metadata: {},
    completedAt: null,
    createdAt: baseDate,
    updatedAt: baseDate,
    ...overrides,
  });

  describe("toGanttTask", (): void => {
    it("should convert a Task with metadata.startDate to GanttTask", (): void => {
      const task = createTask({
        metadata: {
          startDate: "2026-02-05",
        },
        dueDate: new Date("2026-02-15"),
      });

      const ganttTask = toGanttTask(task);

      expect(ganttTask).not.toBeNull();
      expect(ganttTask?.startDate).toBeInstanceOf(Date);
      expect(ganttTask?.endDate).toBeInstanceOf(Date);
      expect(ganttTask?.startDate.getTime()).toBe(new Date("2026-02-05").getTime());
      expect(ganttTask?.endDate.getTime()).toBe(new Date("2026-02-15").getTime());
    });

    it("should use createdAt as startDate if metadata.startDate is not provided", (): void => {
      const task = createTask({
        createdAt: new Date("2026-02-01"),
        dueDate: new Date("2026-02-15"),
      });

      const ganttTask = toGanttTask(task);

      expect(ganttTask).not.toBeNull();
      expect(ganttTask?.startDate.getTime()).toBe(new Date("2026-02-01").getTime());
    });

    it("should use current date as endDate if dueDate is null", (): void => {
      const beforeConversion = Date.now();
      const task = createTask({
        dueDate: null,
        metadata: {
          startDate: "2026-02-01",
        },
      });

      const ganttTask = toGanttTask(task);
      const afterConversion = Date.now();

      expect(ganttTask).not.toBeNull();
      expect(ganttTask?.endDate.getTime()).toBeGreaterThanOrEqual(beforeConversion);
      expect(ganttTask?.endDate.getTime()).toBeLessThanOrEqual(afterConversion);
    });

    it("should extract dependencies from metadata", (): void => {
      const task = createTask({
        metadata: {
          startDate: "2026-02-01",
          dependencies: ["task-a", "task-b"],
        },
        dueDate: new Date("2026-02-15"),
      });

      const ganttTask = toGanttTask(task);

      expect(ganttTask).not.toBeNull();
      expect(ganttTask?.dependencies).toEqual(["task-a", "task-b"]);
    });

    it("should handle missing dependencies in metadata", (): void => {
      const task = createTask({
        metadata: {
          startDate: "2026-02-01",
        },
        dueDate: new Date("2026-02-15"),
      });

      const ganttTask = toGanttTask(task);

      expect(ganttTask).not.toBeNull();
      expect(ganttTask?.dependencies).toBeUndefined();
    });

    it("should handle non-array dependencies in metadata", (): void => {
      const task = createTask({
        metadata: {
          startDate: "2026-02-01",
          dependencies: "not-an-array",
        },
        dueDate: new Date("2026-02-15"),
      });

      const ganttTask = toGanttTask(task);

      expect(ganttTask).not.toBeNull();
      expect(ganttTask?.dependencies).toBeUndefined();
    });

    it("should extract isMilestone from metadata", (): void => {
      const task = createTask({
        metadata: {
          startDate: "2026-02-01",
          isMilestone: true,
        },
        dueDate: new Date("2026-02-15"),
      });

      const ganttTask = toGanttTask(task);

      expect(ganttTask).not.toBeNull();
      expect(ganttTask?.isMilestone).toBe(true);
    });

    it("should default isMilestone to false when not specified", (): void => {
      const task = createTask({
        metadata: {
          startDate: "2026-02-01",
        },
        dueDate: new Date("2026-02-15"),
      });

      const ganttTask = toGanttTask(task);

      expect(ganttTask).not.toBeNull();
      expect(ganttTask?.isMilestone).toBe(false);
    });

    it("should handle non-boolean isMilestone in metadata", (): void => {
      const task = createTask({
        metadata: {
          startDate: "2026-02-01",
          isMilestone: "yes",
        },
        dueDate: new Date("2026-02-15"),
      });

      const ganttTask = toGanttTask(task);

      expect(ganttTask).not.toBeNull();
      expect(ganttTask?.isMilestone).toBe(false);
    });

    it("should preserve all original task properties", (): void => {
      const task = createTask({
        id: "special-task",
        title: "Special Task",
        description: "This is special",
        status: TaskStatus.IN_PROGRESS,
        priority: TaskPriority.HIGH,
        metadata: {
          startDate: "2026-02-01",
        },
      });

      const ganttTask = toGanttTask(task);

      expect(ganttTask).not.toBeNull();
      expect(ganttTask?.id).toBe("special-task");
      expect(ganttTask?.title).toBe("Special Task");
      expect(ganttTask?.description).toBe("This is special");
      expect(ganttTask?.status).toBe(TaskStatus.IN_PROGRESS);
      expect(ganttTask?.priority).toBe(TaskPriority.HIGH);
    });
  });

  describe("toGanttTasks", (): void => {
    it("should convert multiple tasks to GanttTasks", (): void => {
      const tasks = [
        createTask({
          id: "task-1",
          metadata: { startDate: "2026-02-01" },
          dueDate: new Date("2026-02-10"),
        }),
        createTask({
          id: "task-2",
          metadata: { startDate: "2026-02-11" },
          dueDate: new Date("2026-02-20"),
        }),
      ];

      const ganttTasks = toGanttTasks(tasks);

      expect(ganttTasks).toHaveLength(2);
      expect(ganttTasks[0]?.id).toBe("task-1");
      expect(ganttTasks[1]?.id).toBe("task-2");
    });

    it("should filter out tasks that cannot be converted", (): void => {
      const tasks = [
        createTask({
          id: "task-1",
          metadata: { startDate: "2026-02-01" },
          dueDate: new Date("2026-02-10"),
        }),
        createTask({
          id: "task-2",
          metadata: { startDate: "2026-02-11" },
          dueDate: new Date("2026-02-20"),
        }),
      ];

      const ganttTasks = toGanttTasks(tasks);

      // All valid tasks should be converted
      expect(ganttTasks).toHaveLength(2);
    });

    it("should handle empty array", (): void => {
      const ganttTasks = toGanttTasks([]);

      expect(ganttTasks).toEqual([]);
    });

    it("should maintain order of tasks", (): void => {
      const tasks = [
        createTask({ id: "first", metadata: { startDate: "2026-03-01" } }),
        createTask({ id: "second", metadata: { startDate: "2026-02-01" } }),
        createTask({ id: "third", metadata: { startDate: "2026-01-01" } }),
      ];

      const ganttTasks = toGanttTasks(tasks);

      expect(ganttTasks[0]?.id).toBe("first");
      expect(ganttTasks[1]?.id).toBe("second");
      expect(ganttTasks[2]?.id).toBe("third");
    });
  });
});
