import { describe, expect, it } from "vitest";
import { planWorkBlocksIntentSchema } from "@/lib/intent";
import { buildWorkPlan } from "@/lib/work-planner";

function dayKey(iso: string) {
  return new Date(iso).toISOString().slice(0, 10);
}

function isoWeekKey(iso: string) {
  const date = new Date(iso);
  const utc = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
  const dayNum = utc.getUTCDay() || 7;
  utc.setUTCDate(utc.getUTCDate() + 4 - dayNum);
  const yearStart = new Date(Date.UTC(utc.getUTCFullYear(), 0, 1));
  const weekNo = Math.ceil((((utc.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
  return `${utc.getUTCFullYear()}-W${String(weekNo).padStart(2, "0")}`;
}

describe("work planner", () => {
  it("honors weekly cadence distribution", () => {
    const now = new Date("2026-04-01T08:00:00.000Z");

    const intent = planWorkBlocksIntentSchema.parse({
      intent: "plan_work_blocks",
      task_title: "Projet cadence",
      deadline: "2026-04-30T18:00:00.000Z",
      timezone: "Europe/Paris",
      total_effort_minutes: 240,
      preferred_block_minutes: 60,
      cadence_type: "weekly",
      cadence_per_week_target_minutes: 60,
      preferred_days: [],
      confidence: 0.9,
      constraints: {
        work_day_start_hour: 9,
        work_day_end_hour: 18,
        excluded_weekdays: [0, 6],
        min_break_minutes: 0,
        strategy: "spread"
      }
    });

    const plan = buildWorkPlan({
      provider: "google",
      intent,
      busySlots: [],
      now
    });

    const weekKeys = new Set(
      plan.blocks.map((block) => isoWeekKey(block.start))
    );

    expect(plan.diagnostics.cadence_type).toBe("weekly");
    expect(plan.blocks.length).toBeGreaterThanOrEqual(3);
    expect(weekKeys.size).toBeGreaterThanOrEqual(3);
  });

  it("spreads blocks across days when strategy is spread", () => {
    const now = new Date("2026-04-06T08:00:00.000Z");

    const intent = planWorkBlocksIntentSchema.parse({
      intent: "plan_work_blocks",
      task_title: "Dossier client",
      deadline: "2026-04-09T18:00:00.000Z",
      timezone: "Europe/Paris",
      total_effort_minutes: 240,
      preferred_block_minutes: 60,
      constraints: {
        work_day_start_hour: 9,
        work_day_end_hour: 18,
        excluded_weekdays: [0, 6],
        min_break_minutes: 0,
        strategy: "spread"
      }
    });

    const plan = buildWorkPlan({
      provider: "google",
      intent,
      busySlots: [],
      now
    });

    const uniqueDays = new Set(plan.blocks.map((block) => dayKey(block.start)));
    expect(plan.blocks.length).toBeGreaterThan(0);
    expect(uniqueDays.size).toBeGreaterThan(1);
  });

  it("packs earlier slots when strategy is compact", () => {
    const now = new Date("2026-04-06T08:00:00.000Z");

    const spreadIntent = planWorkBlocksIntentSchema.parse({
      intent: "plan_work_blocks",
      task_title: "Dossier client",
      deadline: "2026-04-09T18:00:00.000Z",
      timezone: "Europe/Paris",
      total_effort_minutes: 240,
      preferred_block_minutes: 60,
      constraints: {
        work_day_start_hour: 9,
        work_day_end_hour: 18,
        excluded_weekdays: [0, 6],
        min_break_minutes: 0,
        strategy: "spread"
      }
    });

    const compactIntent = {
      ...spreadIntent,
      constraints: {
        ...spreadIntent.constraints,
        strategy: "compact" as const
      }
    };

    const spreadPlan = buildWorkPlan({
      provider: "google",
      intent: spreadIntent,
      busySlots: [],
      now
    });

    const compactPlan = buildWorkPlan({
      provider: "google",
      intent: compactIntent,
      busySlots: [],
      now
    });

    const spreadUniqueDays = new Set(spreadPlan.blocks.map((block) => dayKey(block.start)));
    const compactUniqueDays = new Set(compactPlan.blocks.map((block) => dayKey(block.start)));

    expect(compactPlan.blocks.length).toBe(spreadPlan.blocks.length);
    expect(compactUniqueDays.size).toBeLessThanOrEqual(spreadUniqueDays.size);
  });

  it("avoids busy slots and caps oversized plans", () => {
    const now = new Date("2026-04-06T08:00:00.000Z");

    const intent = planWorkBlocksIntentSchema.parse({
      intent: "plan_work_blocks",
      task_title: "Refonte app",
      deadline: "2026-04-20T18:00:00.000Z",
      timezone: "Europe/Paris",
      total_effort_minutes: 4000,
      preferred_block_minutes: 30,
      constraints: {
        work_day_start_hour: 9,
        work_day_end_hour: 18,
        excluded_weekdays: [0, 6],
        min_break_minutes: 0,
        strategy: "compact"
      }
    });

    const plan = buildWorkPlan({
      provider: "outlook",
      intent,
      busySlots: [
        {
          start: "2026-04-06T09:00:00.000Z",
          end: "2026-04-06T11:00:00.000Z"
        }
      ],
      now
    });

    const busyStart = new Date("2026-04-06T09:00:00.000Z");
    const busyEnd = new Date("2026-04-06T11:00:00.000Z");
    const hasOverlapWithBusySlot = plan.blocks.some((block) => {
      const start = new Date(block.start);
      const end = new Date(block.end);
      return start < busyEnd && busyStart < end;
    });

    expect(plan.blocks.length).toBeLessThanOrEqual(24);
    expect(hasOverlapWithBusySlot).toBe(false);
  });
});
