"use client";

import { useEffect, useMemo, useState } from "react";
import { ProjectPlanningBoard } from "@/components/project-planning-board";
import { getDefaultProjectTaskRows, type TaskRow } from "@/components/project-task-table";

type Project = {
  id: string;
  name: string;
  client: string;
  manager: string;
  budget: string;
  progress: number;
  temperature: string;
  tone: "neutral" | "green" | "yellow" | "orange" | "red" | "blue";
  riskLabel?: string;
  riskTone?: "neutral" | "green" | "yellow" | "orange" | "red" | "blue";
  poles: string[];
  nextMilestone: string;
  nextMilestoneDate: string;
};

type Planning = {
  projectId: string;
  status: string;
  rest: string;
  weeks: number[];
  team: Array<{ name: string; role: string; weekly: number[] }>;
  phases: Array<{
    name: string;
    from: string;
    to: string;
    tasks: string[];
    milestone: string;
    startDate?: string;
    endDate?: string;
    milestoneDate?: string;
  }>;
};

export function ProjectWorkspace({ projects, planning }: { projects: Project[]; planning: Planning[] }) {
  const [rowsByProject, setRowsByProject] = useState<Record<string, TaskRow[]>>({});
  const projectIds = useMemo(() => projects.map((project) => project.id), [projects]);
  const syncedPlanning = projects.map((project, index) => {
    const existingPlanning = planning.find((item) => item.projectId === project.id);
    const editedRows = rowsByProject[project.id];

    return editedRows ? buildPlanningFromRows(project, existingPlanning, editedRows, index) : existingPlanning ?? buildPlanningFromRows(project, undefined, getDefaultProjectTaskRows(), index);
  });

  useEffect(() => {
    let isActive = true;

    async function loadSavedRows() {
      if (projectIds.length === 0) {
        return;
      }

      try {
        const response = await fetch(`/api/project-task-rows?projectIds=${encodeURIComponent(projectIds.join(","))}`);

        if (!response.ok) {
          return;
        }

        const data = (await response.json()) as { rowsByProject?: Record<string, TaskRow[]> };

        if (isActive && data.rowsByProject) {
          setRowsByProject(data.rowsByProject);
        }
      } catch {
        // The table stays usable with demo rows if the local database is not available yet.
      }
    }

    void loadSavedRows();

    return () => {
      isActive = false;
    };
  }, [projectIds]);

  return (
    <div className="w-full">
      <ProjectPlanningBoard projects={projects} planning={syncedPlanning} />
    </div>
  );
}

function buildPlanningFromRows(project: Project, existing: Planning | undefined, rows: TaskRow[], index: number): Planning {
  const weeks = Array.from({ length: 52 }, () => 0);
  const team = getProjectTeam(project, existing);

  const teamWeekly = team.map((member) => ({
    ...member,
    weekly: Array.from({ length: 52 }, () => 0)
  }));

  for (const row of rows) {
    const weekIndex = getWeekIndex(row.start) ?? index % 10;

    row.allocations.slice(0, 4).forEach((value, memberIndex) => {
      const planned = value * row.quantity;
      weeks[weekIndex] += planned;

      if (teamWeekly[memberIndex]) {
        teamWeekly[memberIndex].weekly[weekIndex] += planned;
      }
    });
  }

  const phases = buildPhasesFromRows(rows);
  const totalDays = weeks.reduce((sum, value) => sum + value, 0);
  const plannedTarget =
    existing?.weeks.reduce((sum, value) => sum + value, 0) || Math.max(18, Math.ceil(totalDays + 6));

  return {
    projectId: project.id,
    status: existing?.status ?? "En cours",
    rest: `${Math.max(0, Math.round(plannedTarget - totalDays))} j`,
    weeks,
    team: teamWeekly,
    phases
  };
}

function getProjectTeam(project: Project, existing: Planning | undefined) {
  const existingTeam = existing?.team ?? [];
  const fallback = [{ name: project.manager, role: "CP" }];
  const team = [...existingTeam, ...fallback].filter(
    (member, index, array) => array.findIndex((candidate) => candidate.name === member.name) === index
  );

  return [...team, { name: "TJM3", role: "" }, { name: "TJM4", role: "" }].slice(0, 4);
}

function buildPhasesFromRows(rows: TaskRow[]) {
  const phaseMap = new Map<string, TaskRow[]>();

  for (const row of rows) {
    phaseMap.set(row.phase, [...(phaseMap.get(row.phase) ?? []), row]);
  }

  return Array.from(phaseMap.entries()).map(([phase, phaseRows]) => {
    const weekIndexes = phaseRows
      .map((row) => getWeekIndex(row.start) ?? getWeekIndex(row.end))
      .filter((value): value is number => typeof value === "number");
    const from = Math.min(...(weekIndexes.length ? weekIndexes : [0]));
    const to = Math.max(...(weekIndexes.length ? weekIndexes : [from + 1]));

    return {
      name: phase,
      from: `S${from + 1}`,
      to: `S${to + 1}`,
      tasks: Array.from(new Set(phaseRows.map((row) => row.step))),
      milestone: phaseRows[phaseRows.length - 1]?.step ?? phase
    };
  });
}

function getWeekIndex(dateValue?: string) {
  if (!dateValue) {
    return undefined;
  }

  const date = parseLooseDate(dateValue);

  if (!date || Number.isNaN(date.getTime())) {
    return undefined;
  }

  return Math.max(0, Math.min(51, getIsoWeek(date) - 1));
}

function parseLooseDate(value: string) {
  const trimmed = value.trim();
  const frenchMatch = trimmed.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);

  if (frenchMatch) {
    const [, day, month, year] = frenchMatch;
    return new Date(Number(year), Number(month) - 1, Number(day));
  }

  const isoMatch = trimmed.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);

  if (isoMatch) {
    const [, year, month, day] = isoMatch;
    return new Date(Number(year), Number(month) - 1, Number(day));
  }

  return new Date(trimmed);
}

function getIsoWeek(date: Date) {
  const copy = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
  const day = copy.getUTCDay() || 7;
  copy.setUTCDate(copy.getUTCDate() + 4 - day);
  const yearStart = new Date(Date.UTC(copy.getUTCFullYear(), 0, 1));
  return Math.ceil(((copy.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
}
