import { Search, X } from "lucide-react";
import { useMemo, useState, type CSSProperties } from "react";
import { createPortal } from "react-dom";

import {
  allocatedHoursInRange,
  buildAllocationBarSegment,
  formatAllocationEffort,
  formatHoursAmount,
  hoursPerDayFromAllocation,
  projectBarStyle,
  roundToHalfHour,
  visibleWeekdayCount,
  type EffortDisplayMode,
} from "../../planner/allocationTimeline";
import type { Allocation, Person, Project } from "../../types";
import { Avatar } from "../ui/Avatar";

export interface CloneModeContext {
  allocation: Allocation;
  projectId: number;
  projectName: string;
}

type CloneTargetMode = "people" | "projects";

interface AllocationCloneModeProps {
  context: CloneModeContext;
  people: Person[];
  projects: Project[];
  allocations: Allocation[];
  dayDates: Date[];
  effortMode: EffortDisplayMode;
  onCloneToPerson: (personId: number) => void;
  onCloneToProject: (projectId: number) => void;
  onExit: () => void;
}

function freeHoursLabel(
  person: Person,
  personAllocations: Allocation[],
  dayDates: Date[],
  rangeStart: string,
  rangeEnd: string,
): { label: string; tone: "free" | "over" | "off" } {
  const weekdayCount = visibleWeekdayCount(dayDates, rangeStart, rangeEnd);
  if (weekdayCount <= 0) return { label: "Off", tone: "off" };
  const capacity = roundToHalfHour((person.weekly_capacity_hrs / 5) * weekdayCount);
  let allocated = 0;
  for (const allocation of personAllocations) {
    const overlapStart = allocation.start_date > rangeStart ? allocation.start_date : rangeStart;
    const overlapEnd = allocation.end_date < rangeEnd ? allocation.end_date : rangeEnd;
    if (overlapStart > overlapEnd) continue;
    const days = visibleWeekdayCount(dayDates, overlapStart, overlapEnd);
    allocated += allocatedHoursInRange(allocation.allocation_pct, person.weekly_capacity_hrs, days);
  }
  const free = roundToHalfHour(capacity - allocated);
  if (free < 0) return { label: `${formatHoursAmount(Math.abs(free))} over`, tone: "over" };
  if (free === 0) return { label: "0h free", tone: "off" };
  return { label: `${formatHoursAmount(free)} free`, tone: "free" };
}

export function AllocationCloneMode({
  context,
  people,
  projects,
  allocations,
  dayDates,
  effortMode,
  onCloneToPerson,
  onCloneToProject,
  onExit,
}: AllocationCloneModeProps) {
  const [targetMode, setTargetMode] = useState<CloneTargetMode>("people");
  const [search, setSearch] = useState("");

  const sourcePerson = people.find((person) => person.id === context.allocation.person_id);
  const weekdayCount = visibleWeekdayCount(
    dayDates,
    context.allocation.start_date,
    context.allocation.end_date,
  );
  const cloningLabel = sourcePerson
    ? formatAllocationEffort(
        effortMode,
        context.allocation.allocation_pct,
        sourcePerson.weekly_capacity_hrs,
        weekdayCount,
      )
    : `${context.allocation.allocation_pct}%`;

  const assignmentLabel =
    weekdayCount === 1
      ? "1 weekday assignment"
      : `${weekdayCount} weekday assignment${weekdayCount === 1 ? "" : "s"}`;

  const term = search.trim().toLowerCase();
  const filteredPeople = useMemo(
    () =>
      people.filter((person) => {
        if (!person.is_active) return false;
        if (!term) return true;
        return (
          person.name.toLowerCase().includes(term) ||
          person.role.name.toLowerCase().includes(term) ||
          person.email.toLowerCase().includes(term)
        );
      }),
    [people, term],
  );

  const filteredProjects = useMemo(
    () =>
      projects.filter((project) => {
        if (!project.is_active) return false;
        if (!term) return true;
        return project.name.toLowerCase().includes(term) || project.type.toLowerCase().includes(term);
      }),
    [projects, term],
  );

  const allocationsByPerson = useMemo(() => {
    const map = new Map<number, Allocation[]>();
    for (const allocation of allocations) {
      if (!map.has(allocation.person_id)) map.set(allocation.person_id, []);
      map.get(allocation.person_id)!.push(allocation);
    }
    return map;
  }, [allocations]);

  const totalDays = dayDates.length;

  const panel = (
    <>
      <div className="clone-mode-banner">
        <span>
          <strong>CLONE MODE</strong>
          {" | "}
          {assignmentLabel} from {sourcePerson?.name ?? "Unknown"}
          {sourcePerson ? ` | ${sourcePerson.role.name}` : ""}
          {" | "}
          Cloning {cloningLabel}
        </span>
        <button className="clone-mode-exit" onClick={onExit} type="button">
          Exit
        </button>
      </div>

      <div className="clone-mode-panel">
        <div className="clone-mode-panel-header">
          <div className="clone-mode-panel-title">
            <label className="clone-mode-label" htmlFor="clone-target-mode">
              CLONE TO
            </label>
            <select
              id="clone-target-mode"
              onChange={(event) => setTargetMode(event.target.value as CloneTargetMode)}
              value={targetMode}
            >
              <option value="people">People</option>
              <option value="projects">Projects</option>
            </select>
          </div>
          <div className="clone-mode-search">
            <Search aria-hidden size={16} />
            <input
              onChange={(event) => setSearch(event.target.value)}
              placeholder={targetMode === "people" ? "Search people…" : "Search projects…"}
              type="search"
              value={search}
            />
          </div>
          <button aria-label="Close clone panel" className="clone-mode-close" onClick={onExit} type="button">
            <X size={20} />
          </button>
        </div>

        <div className="clone-mode-list">
          {targetMode === "people"
            ? filteredPeople.map((person) => {
                const personAllocations = allocationsByPerson.get(person.id) ?? [];
                const capacity = freeHoursLabel(
                  person,
                  personAllocations,
                  dayDates,
                  context.allocation.start_date,
                  context.allocation.end_date,
                );
                const isSource = person.id === context.allocation.person_id;
                return (
                  <div className="clone-mode-row" key={person.id}>
                    <div className="clone-mode-row-person">
                      <Avatar color={person.avatar_color} name={person.name} size={32} />
                      <div className="person-meta">
                        <strong>{person.name}</strong>
                        <small>{person.role.name}</small>
                      </div>
                    </div>
                    <div className="clone-mode-row-track">
                      <div
                        className="clone-mode-mini-timeline"
                        style={{ "--planner-cols": totalDays } as CSSProperties}
                      >
                        <div className="planner-day-grid" />
                        {personAllocations.map((allocation) => {
                          const segment = buildAllocationBarSegment(
                            dayDates,
                            allocation.start_date,
                            allocation.end_date,
                          );
                          if (!segment) return null;
                          const project = projects.find((item) => item.id === allocation.project_id);
                          return (
                            <div
                              className="clone-mode-mini-bar"
                              key={allocation.id}
                              style={{
                                ...projectBarStyle(segment, totalDays),
                                background: project?.color ?? "#94a3b8",
                              }}
                              title={project?.name}
                            />
                          );
                        })}
                        <span className={`clone-mode-capacity is-${capacity.tone}`}>{capacity.label}</span>
                      </div>
                    </div>
                    <button
                      className="clone-mode-clone-btn"
                      disabled={isSource}
                      onClick={() => onCloneToPerson(person.id)}
                      title={isSource ? "Already assigned to this person" : undefined}
                      type="button"
                    >
                      Clone
                    </button>
                  </div>
                );
              })
            : filteredProjects.map((project) => {
                const isSource = project.id === context.projectId;
                return (
                  <div className="clone-mode-row" key={project.id}>
                    <div className="clone-mode-row-person">
                      <span className="clone-mode-project-dot" style={{ background: project.color }} />
                      <div className="person-meta">
                        <strong>{project.name}</strong>
                        <small>{project.type}</small>
                      </div>
                    </div>
                    <div className="clone-mode-row-track" />
                    <button
                      className="clone-mode-clone-btn"
                      disabled={isSource}
                      onClick={() => onCloneToProject(project.id)}
                      title={isSource ? "Already on this project" : undefined}
                      type="button"
                    >
                      Clone
                    </button>
                  </div>
                );
              })}
        </div>
      </div>
    </>
  );

  return createPortal(panel, document.body);
}

export function cloneModeEffortSummary(allocation: Allocation, person: Person): string {
  const daily = roundToHalfHour(
    hoursPerDayFromAllocation(allocation.allocation_pct, person.weekly_capacity_hrs),
  );
  return formatHoursAmount(daily);
}
