"use client";

import { CalendarDays } from "lucide-react";
import { useMemo, useState } from "react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";

export type TaskStatus = "Terminé" | "En cours" | "Non réalisé";
export type Displacement = "Oui" | "Non";
type ProjectOption = { id: string; name: string; client: string };
type ProjectTeam = Record<string, Array<{ name: string; role: string }>>;

export type TaskRow = {
  phase: string;
  step: string;
  allocations: number[];
  quantity: number;
  start?: string;
  end?: string;
  displacement: Displacement;
  status: TaskStatus;
};

const phaseTones: Record<string, string> = {
  Lancement: "border-[#cce3b7] bg-[#e6f3d8] text-[#315c24]",
  "Audit & Wireframes": "border-[#bdd4f6] bg-[#e8f1ff] text-[#263b67]",
  "Prototype & test": "border-[#b9e4df] bg-[#e7f8f4] text-[#116f65]",
  Transmission: "border-[#add6f4] bg-[#dff1ff] text-[#205a8c]"
};

const statusTones: Record<TaskStatus, string> = {
  Terminé: "border-[#b7e3a7] bg-[#d9f1c4] text-[#23823a]",
  "En cours": "border-[#9ccaf0] bg-[#d9efff] text-[#176db3]",
  "Non réalisé": "border-[#f4b0aa] bg-[#ffd8d4] text-[#c01818]"
};

const displacementTones: Record<Displacement, string> = {
  Oui: "border-[#b7e3a7] bg-[#d9f1c4] text-[#23823a]",
  Non: "border-[#f4b0aa] bg-[#ffd8d4] text-[#c01818]"
};

const baseRows: TaskRow[] = [
  { phase: "Lancement", step: "Réunion de lancement", allocations: [0.15, 0, 0, 0], quantity: 1, start: "2026-04-06", end: "2026-04-06", displacement: "Non", status: "Terminé" },
  { phase: "Lancement", step: "Réunion de lancement", allocations: [0.15, 0.15, 0, 0], quantity: 1, start: "2026-04-08", end: "2026-04-08", displacement: "Oui", status: "Terminé" },
  { phase: "Lancement", step: "Réunion de lancement", allocations: [0.15, 0, 0, 0], quantity: 1, start: "2026-04-09", end: "2026-04-09", displacement: "Non", status: "Terminé" },
  { phase: "Lancement", step: "Imprégnation", allocations: [0.3, 0.3, 0, 0], quantity: 1, displacement: "Non", status: "Terminé" },
  { phase: "Lancement", step: "Imprégnation", allocations: [0.15, 0.5, 0, 0], quantity: 1, displacement: "Non", status: "Terminé" },
  { phase: "Audit & Wireframes", step: "Audit", allocations: [2, 2, 0, 0], quantity: 1, start: "2026-04-16", end: "2026-04-16", displacement: "Non", status: "Terminé" },
  { phase: "Audit & Wireframes", step: "Wireframes", allocations: [0.3, 2, 0, 0], quantity: 1, displacement: "Non", status: "En cours" },
  { phase: "Audit & Wireframes", step: "Atelier de co-design", allocations: [0, 0.15, 0, 0], quantity: 1, displacement: "Non", status: "En cours" },
  { phase: "Audit & Wireframes", step: "Atelier de co-design", allocations: [0.3, 0.3, 0, 0], quantity: 1, displacement: "Oui", status: "Non réalisé" },
  { phase: "Prototype & test", step: "Maquettes", allocations: [0.3, 2.5, 0, 0], quantity: 1, displacement: "Non", status: "Non réalisé" },
  { phase: "Prototype & test", step: "Atelier prototype", allocations: [0, 0.15, 0, 0], quantity: 1, displacement: "Non", status: "Non réalisé" },
  { phase: "Prototype & test", step: "Tests utilisateurs", allocations: [0.3, 0.3, 0, 0], quantity: 1, displacement: "Oui", status: "Non réalisé" },
  { phase: "Transmission", step: "Dossier de synthèse", allocations: [0.3, 1.5, 0, 0], quantity: 1, displacement: "Non", status: "Non réalisé" },
  { phase: "Transmission", step: "Transmission", allocations: [0.3, 0.3, 0, 0], quantity: 1, displacement: "Oui", status: "Non réalisé" }
];

export function getDefaultProjectTaskRows() {
  return baseRows.map((row) => ({ ...row, allocations: [...row.allocations] }));
}

export function ProjectTaskTable({
  projects = [],
  teamsByProject = {},
  rowsByProject = {},
  onProjectRowsChange
}: {
  projects?: ProjectOption[];
  teamsByProject?: ProjectTeam;
  rowsByProject?: Record<string, TaskRow[]>;
  onProjectRowsChange?: (projectId: string, rows: TaskRow[]) => void;
}) {
  const [selectedProjectId, setSelectedProjectId] = useState(projects[0]?.id ?? "");
  const [isEditing, setIsEditing] = useState(false);
  const selectedProject = projects.find((project) => project.id === selectedProjectId) ?? projects[0];
  const teamMembers = getTeamMembers(selectedProjectId, selectedProject, teamsByProject);
  const rows = rowsByProject[selectedProjectId] ?? getDefaultProjectTaskRows();
  const totals = useMemo(
    () =>
      rows.reduce(
        (acc, row) => {
          acc.allocations = acc.allocations.map((value, index) => value + getAllocation(row, index));
          acc.days += getTotalDays(row);
          return acc;
        },
        { allocations: [0, 0, 0, 0], days: 0 }
      ),
    [rows]
  );

  function updateRow(index: number, patch: Partial<TaskRow>) {
    const projectRows = rowsByProject[selectedProjectId] ?? getDefaultProjectTaskRows();
    onProjectRowsChange?.(selectedProjectId, projectRows.map((row, rowIndex) => (rowIndex === index ? { ...row, ...patch } : row)));
  }

  return (
    <section className="w-full px-3 py-4 lg:px-5">
      <div className="rounded-lg border border-border bg-white">
        <div className="flex flex-wrap items-center justify-between gap-2 border-b border-border p-3">
          <div className="flex flex-wrap items-center gap-2">
            <select
              className="h-9 min-w-80 rounded-md border border-border bg-white px-3 text-sm font-semibold text-[#272445]"
              value={selectedProjectId}
              onChange={(event) => setSelectedProjectId(event.target.value)}
              disabled={projects.length === 0}
            >
              {projects.map((project) => (
                <option key={project.id} value={project.id}>
                  {project.client} - {project.name}
                </option>
              ))}
            </select>
            <Button type="button" variant={isEditing ? "primary" : "secondary"} onClick={() => setIsEditing((value) => !value)}>
              {isEditing ? "Quitter édition" : "Mode édition"}
            </Button>
            <Badge tone="blue">{formatNumber(totals.days)} j</Badge>
          </div>
        </div>
        <div className="overflow-x-auto">
          <table className="w-full min-w-[1320px] border-collapse text-sm">
            <thead className="bg-[#356f56] text-left text-sm font-bold text-white">
              <tr>
                <th className="w-48 border-r border-white/30 px-3 py-3">Phase</th>
                <th className="w-60 px-3 py-3">Étape</th>
                {teamMembers.map((member) => (
                  <th key={member.name} className="w-28 px-3 py-3 text-right">
                    {member.name}
                  </th>
                ))}
                <th className="w-16 px-3 py-3 text-right">Qté</th>
                <th className="w-24 px-3 py-3 text-right">T Total</th>
                <th className="w-36 px-3 py-3">Début estimé</th>
                <th className="w-36 px-3 py-3">Fin estimé</th>
                <th className="w-40 px-3 py-3">Déplacement</th>
                <th className="w-40 px-3 py-3">État</th>
              </tr>
            </thead>
            <tbody>
              {rows.map((row, index) => (
                <tr key={`task-row-${index}`} className={index % 2 === 0 ? "bg-white" : "bg-[#f4f6f7]"}>
                  <td className="border-r border-[#d1ddd8] px-3 py-2">
                    {isEditing ? (
                      <TextInput value={row.phase} className={phaseTones[row.phase] ?? phaseTones.Lancement} onChange={(value) => updateRow(index, { phase: value })} />
                    ) : (
                      <ReadPill className={phaseTones[row.phase] ?? phaseTones.Lancement}>{row.phase}</ReadPill>
                    )}
                  </td>
                  <td className="px-3 py-2">
                    {isEditing ? (
                      <TextInput value={row.step} className="border-[#d8dce0] bg-[#edf0f2] text-[#4a4a4a]" onChange={(value) => updateRow(index, { step: value })} />
                    ) : (
                      <ReadPill className="border-[#d8dce0] bg-[#edf0f2] text-[#4a4a4a]">{row.step}</ReadPill>
                    )}
                  </td>
                  {teamMembers.map((member, memberIndex) => (
                    <EditableNumberCell
                      key={member.name}
                      isEditing={isEditing}
                      value={getAllocation(row, memberIndex)}
                      onChange={(value) => updateRow(index, { allocations: updateAllocation(row.allocations, memberIndex, value) })}
                    />
                  ))}
                  <EditableNumberCell isEditing={isEditing} value={row.quantity} onChange={(value) => updateRow(index, { quantity: value || 1 })} />
                  <NumberCell value={getTotalDays(row)} />
                  <td className="px-3 py-2">
                    <DateInput value={row.start} onChange={(value) => updateRow(index, { start: value })} />
                  </td>
                  <td className="px-3 py-2">
                    <DateInput value={row.end} onChange={(value) => updateRow(index, { end: value })} />
                  </td>
                  <td className="px-3 py-2">
                    <SelectPill
                      className={displacementTones[row.displacement]}
                      value={row.displacement}
                      onChange={(value) => updateRow(index, { displacement: value as Displacement })}
                      options={["Oui", "Non"]}
                    />
                  </td>
                  <td className="px-3 py-2">
                    <SelectPill
                      className={statusTones[row.status]}
                      value={row.status}
                      onChange={(value) => updateRow(index, { status: value as TaskStatus })}
                      options={["Terminé", "En cours", "Non réalisé"]}
                    />
                  </td>
                </tr>
              ))}
            </tbody>
            <tfoot className="bg-[#d7e4dd] font-bold">
              <tr>
                <td />
                <td className="px-3 py-3 text-right">Total</td>
                {teamMembers.map((member, index) => (
                  <td key={member.name} className="px-3 py-3 text-right">
                    {formatNumber(totals.allocations[index] ?? 0)}
                  </td>
                ))}
                <td />
                <td className="px-3 py-3 text-right">{formatNumber(totals.days)}</td>
                <td colSpan={4} />
              </tr>
            </tfoot>
          </table>
        </div>
      </div>
    </section>
  );
}

function ReadPill({ className, children }: { className: string; children: React.ReactNode }) {
  return <span className={cn("inline-flex h-6 w-full items-center rounded-full border px-2 text-sm font-bold", className)}>{children}</span>;
}

function TextInput({ className, value, onChange }: { className: string; value: string; onChange: (value: string) => void }) {
  return (
    <input
      className={cn("h-6 w-full rounded-full border px-2 text-sm font-bold outline-none", className)}
      value={value}
      onChange={(event) => onChange(event.target.value)}
    />
  );
}

function DateInput({ value, onChange }: { value?: string; onChange: (value: string) => void }) {
  const displayValue = formatDateForDisplay(value);

  return (
    <div className="flex h-8 items-center gap-1 rounded-sm border border-transparent px-1 hover:border-border focus-within:border-[#272445] focus-within:bg-white">
      <input
        className="h-7 min-w-0 flex-1 bg-transparent px-1 text-sm outline-none"
        inputMode="numeric"
        placeholder="jj/mm/aaaa"
        type="text"
        value={displayValue}
        onChange={(event) => onChange(formatDateTyping(event.target.value))}
      />
      <label className="relative flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-sm text-[#272445] hover:bg-[#f3eff8]">
        <CalendarDays className="h-4 w-4" />
        <input
          aria-label="Choisir une date"
          className="absolute inset-0 cursor-pointer opacity-0"
          tabIndex={-1}
          type="date"
          value={toIsoDate(value)}
          onChange={(event) => onChange(fromIsoDate(event.target.value))}
        />
      </label>
    </div>
  );
}

function SelectPill({
  className,
  value,
  options,
  onChange
}: {
  className: string;
  value: string;
  options: string[];
  onChange: (value: string) => void;
}) {
  return (
    <select
      className={cn("h-6 w-full rounded-full border px-2 text-sm font-bold outline-none", className)}
      value={value}
      onChange={(event) => onChange(event.target.value)}
    >
      {options.map((option) => (
        <option key={option} value={option}>
          {option}
        </option>
      ))}
    </select>
  );
}

function NumberCell({ value }: { value?: number }) {
  return <td className="px-3 py-2 text-right">{value ? formatNumber(value) : ""}</td>;
}

function getTotalDays(row: TaskRow) {
  return row.allocations.reduce((sum, value) => sum + value, 0) * row.quantity;
}

function formatNumber(value: number) {
  return value.toLocaleString("fr-FR", { maximumFractionDigits: 2, minimumFractionDigits: value % 1 ? 2 : 0 });
}

function formatDateTyping(value: string) {
  const digits = value.replace(/\D/g, "").slice(0, 8);
  const parts = [digits.slice(0, 2), digits.slice(2, 4), digits.slice(4, 8)].filter(Boolean);
  return parts.join("/");
}

function formatDateForDisplay(value?: string) {
  if (!value) {
    return "";
  }

  if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(value)) {
    return value;
  }

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

  if (isoMatch) {
    const [, year, month, day] = isoMatch;
    return `${day.padStart(2, "0")}/${month.padStart(2, "0")}/${year}`;
  }

  return value;
}

function toIsoDate(value?: string) {
  if (!value) {
    return "";
  }

  const displayValue = formatDateForDisplay(value);
  const match = displayValue.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);

  if (!match) {
    return "";
  }

  const [, day, month, year] = match;
  return `${year}-${month.padStart(2, "0")}-${day.padStart(2, "0")}`;
}

function fromIsoDate(value: string) {
  const match = value.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);

  if (!match) {
    return "";
  }

  const [, year, month, day] = match;
  return `${day.padStart(2, "0")}/${month.padStart(2, "0")}/${year}`;
}

function EditableNumberCell({
  isEditing,
  value,
  onChange
}: {
  isEditing: boolean;
  value?: number;
  onChange: (value: number) => void;
}) {
  if (!isEditing) {
    return <NumberCell value={value} />;
  }

  return (
    <td className="px-3 py-2">
      <input
        className="h-8 w-full rounded-sm border border-border bg-white px-2 text-right text-sm outline-none focus:border-[#272445]"
        min="0"
        step="0.05"
        type="number"
        value={value || ""}
        onChange={(event) => onChange(Number(event.target.value))}
      />
    </td>
  );
}

function getAllocation(row: TaskRow, index: number) {
  return row.allocations[index] ?? 0;
}

function updateAllocation(values: number[], index: number, value: number) {
  const next = [...values];
  next[index] = value;
  return [0, 1, 2, 3].map((slot) => next[slot] ?? 0);
}

function getTeamMembers(projectId: string, selectedProject: ProjectOption | undefined, teamsByProject: ProjectTeam) {
  const team = teamsByProject[projectId] ?? [];
  const fallback = selectedProject ? [{ name: selectedProject.name.includes("HEPPNER") ? "Guillaume Bono" : "Vincent Pujos", role: "CP" }] : [];
  const members = [...team, ...fallback].filter(
    (member, index, array) => array.findIndex((candidate) => candidate.name === member.name) === index
  );
  const padded = [...members, { name: "TJM3", role: "" }, { name: "TJM4", role: "" }].slice(0, 4);

  return padded.map((member, index) => ({
    ...member,
    name: member.name || `TJM${index + 1}`
  }));
}
