import { ChevronRight } from "lucide-react";
import { useMemo } from "react";

import { Avatar } from "../ui/Avatar";
import { AllocationDragTimeline } from "./AllocationDragTimeline";
import type { AllocationDragDraft } from "./AllocationCreatePopover";
import { ProjectCalendarTrack } from "./ProjectCalendarTrack";
import { ProjectRowMenu } from "./ProjectRowMenu";
import { EffortDisplaySelect } from "./EffortDisplaySelect";
import {
  allocatedDaysInRange,
  allocatedHoursInRange,
  formatDaysAmount,
  formatHoursAmount,
  roundToHalfHour,
  visibleWeekdayCount,
  type EffortDisplayMode,
} from "../../planner/allocationTimeline";
import type { Allocation, Person, Project } from "../../types";

export type PlannerViewMode = "timeline" | "phases_milestones";

interface ProjectPlannerBlockProps {
  project: Project;
  teamLabel: string;
  dayDates: Date[];
  plannerView: PlannerViewMode;
  showTentative: boolean;
  expanded: boolean;
  allocations: Allocation[];
  people: Person[];
  peopleById: Map<number, Person>;
  onToggleExpand: () => void;
  onEditProject: () => void;
  onAddPerson: () => void;
  onCreateAllocation: (draft: AllocationDragDraft) => Promise<Allocation | undefined>;
  onUpdateAllocation: (allocation: Allocation, draft: AllocationDragDraft) => void;
  onDeleteAllocation: (allocation: Allocation) => void;
  onTransferAllocation?: (allocation: Allocation, personId: number) => void;
  onStartCloneMode?: (allocation: Allocation) => void;
  cloneSourceAllocationId?: number;
  onExtendAllocationRight?: (allocation: Allocation) => void;
  multiSelectMode?: boolean;
  selectedAllocationIds?: Set<number>;
  onToggleAllocationSelect?: (allocationId: number) => void;
  onToggleMultiSelectMode?: () => void;
  onCreateMilestone: (dueDate: string, name: string, note?: string) => void;
  onCreatePhase: (input: {
    name: string;
    start_date: string;
    end_date: string;
    color?: string;
  }) => void;
  onToggleTentative: () => void;
  onMilestones: () => void;
  onArchive: () => void;
  isSavingAllocation?: boolean;
  isSavingPlanner?: boolean;
  effortMode: EffortDisplayMode;
  onEffortModeChange: (mode: EffortDisplayMode) => void;
  onRestore?: () => void;
}

export function ProjectPlannerBlock({
  project,
  teamLabel,
  dayDates,
  plannerView,
  showTentative,
  expanded,
  allocations,
  people,
  peopleById,
  onToggleExpand,
  onEditProject,
  onAddPerson,
  onCreateAllocation,
  onUpdateAllocation,
  onDeleteAllocation,
  onTransferAllocation,
  onStartCloneMode,
  cloneSourceAllocationId,
  onExtendAllocationRight,
  multiSelectMode = false,
  selectedAllocationIds,
  onToggleAllocationSelect,
  onToggleMultiSelectMode,
  onCreateMilestone,
  onCreatePhase,
  onToggleTentative,
  onMilestones,
  onArchive,
  isSavingAllocation = false,
  isSavingPlanner = false,
  effortMode,
  onEffortModeChange,
  onRestore,
}: ProjectPlannerBlockProps) {
  const showPhasesMilestones = plannerView === "phases_milestones";
  const assignedPersonIds = useMemo(
    () => [...new Set(allocations.map((item) => item.person_id))],
    [allocations],
  );

  const candidatePeople = useMemo(() => {
    const active = people.filter((person) => person.is_active);
    const teamFiltered = project.team_id
      ? active.filter((person) => person.team?.id === project.team_id)
      : active;
    return teamFiltered.filter((person) => !assignedPersonIds.includes(person.id));
  }, [people, project.team_id, assignedPersonIds]);

  const { allocatedHours, capacityHours, allocatedDays, capacityDays, developerCount } = useMemo(() => {
    let allocatedH = 0;
    let allocatedD = 0;
    let capacityH = 0;
    let capacityD = 0;
    const seen = new Set<number>();
    for (const allocation of allocations) {
      const person = peopleById.get(allocation.person_id);
      if (!person) continue;
      seen.add(person.id);
      const days = visibleWeekdayCount(dayDates, allocation.start_date, allocation.end_date);
      const dailyCapacity = roundToHalfHour(person.weekly_capacity_hrs / 5);
      allocatedH += allocatedHoursInRange(allocation.allocation_pct, person.weekly_capacity_hrs, days);
      allocatedD += allocatedDaysInRange(allocation.allocation_pct, days);
      capacityH += dailyCapacity * days;
      capacityD += days;
    }
    return {
      allocatedHours: allocatedH,
      capacityHours: capacityH,
      allocatedDays: allocatedD,
      capacityDays: capacityD,
      developerCount: seen.size,
    };
  }, [allocations, peopleById, dayDates]);

  const effortPct =
    effortMode === "days"
      ? capacityDays > 0
        ? Math.min(100, (allocatedDays / capacityDays) * 100)
        : 0
      : capacityHours > 0
        ? Math.min(100, (allocatedHours / capacityHours) * 100)
        : 0;

  const effortSummary =
    developerCount === 0
      ? "No developers assigned"
      : effortMode === "days"
        ? formatDaysAmount(allocatedDays)
        : formatHoursAmount(allocatedHours);

  const roleGroups = useMemo(() => {
    const map = new Map<string, { roleName: string; allocations: Allocation[] }>();
    for (const allocation of allocations) {
      const person = peopleById.get(allocation.person_id);
      const roleName = person?.role.name ?? "Developer";
      if (!map.has(roleName)) map.set(roleName, { roleName, allocations: [] });
      map.get(roleName)!.allocations.push(allocation);
    }
    if (map.size === 0) map.set("Developer", { roleName: "Developer", allocations: [] });
    return Array.from(map.values()).sort((a, b) => a.roleName.localeCompare(b.roleName));
  }, [allocations, peopleById]);

  return (
    <div className={`planner-project-block ${expanded ? "is-expanded" : ""}`} data-project-id={project.id}>
      <div className={`planner-row planner-project-row ${project.is_active ? "" : "planner-row-archived"}`}>
        <div className="planner-row-label person planner-project-label">
          <button
            aria-expanded={expanded}
            className="planner-project-name"
            onClick={onToggleExpand}
            type="button"
          >
            <span className="project-swatch" style={{ background: project.color }} />
            <div className="person-meta">
              <strong>
                {project.name}
                {project.is_tentative ? (
                  <span className="badge muted" style={{ marginLeft: 6 }}>
                    tentative
                  </span>
                ) : null}
                {!project.is_active ? (
                  <span className="badge muted" style={{ marginLeft: 6 }}>
                    archived
                  </span>
                ) : null}
              </strong>
              <small>{teamLabel}</small>
            </div>
          </button>
          <div className="planner-project-actions">
            <ProjectRowMenu
              onArchive={onArchive}
              onEditDetails={onEditProject}
              onMilestones={onMilestones}
              onRestore={onRestore}
              onToggleTentative={onToggleTentative}
              project={project}
            />
            <button
              aria-expanded={expanded}
              aria-label={expanded ? "Collapse project" : "Expand project"}
              className={`planner-expand-end${expanded ? " expanded" : ""}`}
              onClick={onToggleExpand}
              type="button"
            >
              <ChevronRight size={18} />
            </button>
          </div>
        </div>
        <div className="planner-row-track">
          <ProjectCalendarTrack
            dayDates={dayDates}
            enableMilestones
            isSaving={isSavingPlanner}
            mode="project-line"
            onCreateMilestone={onCreateMilestone}
            onCreatePhase={onCreatePhase}
            project={project}
            showTentative={showTentative}
          />
        </div>
      </div>

      {expanded ? (
        <>
          {showPhasesMilestones ? (
            <div className="planner-row planner-project-subrow planner-phases-row">
              <div className="planner-row-label nested">
                <span className="planner-sub-icon" aria-hidden>
                  ◆
                </span>
                <strong>Phases</strong>
              </div>
              <div className="planner-row-track">
                <ProjectCalendarTrack
                  dayDates={dayDates}
                  enablePhaseDrag
                  isSaving={isSavingPlanner}
                  mode="phases"
                  onCreateMilestone={onCreateMilestone}
                  onCreatePhase={onCreatePhase}
                  project={project}
                  showTentative={showTentative}
                />
              </div>
            </div>
          ) : null}

          <div className="planner-row planner-project-subrow planner-hours-row">
            <div className="planner-row-label nested planner-effort-label">
              <EffortDisplaySelect onChange={onEffortModeChange} value={effortMode} />
              <span className={`planner-effort-total${effortPct > 100 ? " is-over" : ""}`}>{effortSummary}</span>
            </div>
            <div className="planner-row-track">
              <div className="planner-hours-track">
                <div className="planner-hours-bar" style={{ width: `${effortPct}%` }} />
              </div>
            </div>
          </div>

          {roleGroups.map((group) => (
            <div key={group.roleName}>
              <div className="planner-row planner-project-subrow planner-role-row">
                <div className="planner-row-label nested">
                  <span className="planner-sub-icon" aria-hidden>
                    👤
                  </span>
                  <div className="person-meta">
                    <strong>{group.roleName}</strong>
                    <small>
                      {group.allocations.length}/{Math.max(group.allocations.length, 1)}
                    </small>
                  </div>
                </div>
                <div className="planner-row-track">
                  {candidatePeople.length > 0 ? (
                    <AllocationDragTimeline
                      candidatePeople={candidatePeople}
                      color={project.color}
                      dayDates={dayDates}
                      effortMode={effortMode}
                      isSaving={isSavingAllocation}
                      onSave={onCreateAllocation}
                    />
                  ) : null}
                </div>
              </div>

              {group.allocations.map((allocation) => {
                const person = peopleById.get(allocation.person_id);
                if (!person) return null;
                const transferCandidates = people.filter(
                  (candidate) => candidate.is_active && candidate.id !== allocation.person_id,
                );
                return (
                  <div
                    className="planner-row planner-project-subrow planner-member-row"
                    data-allocation-id={allocation.id}
                    data-person-id={allocation.person_id}
                    key={allocation.id}
                  >
                    <div className="planner-row-label nested member">
                      <Avatar color={person.avatar_color} name={person.name} size={26} />
                      <div className="person-meta">
                        <strong>{person.name}</strong>
                        <small>{person.role.name}</small>
                      </div>
                    </div>
                    <div className="planner-row-track">
                      <AllocationDragTimeline
                        allocation={allocation}
                        allocationPct={allocation.allocation_pct}
                        color={project.color}
                        dayDates={dayDates}
                        effortMode={effortMode}
                        fixedPerson={person}
                        isSaving={isSavingAllocation}
                        multiSelectActive={multiSelectMode}
                        cloneSourceId={cloneSourceAllocationId}
                        onStartClone={onStartCloneMode ? () => onStartCloneMode(allocation) : undefined}
                        onDelete={(item) => onDeleteAllocation(item)}
                        onSave={onCreateAllocation}
                        onSelectAllToRight={
                          onExtendAllocationRight ? () => onExtendAllocationRight(allocation) : undefined
                        }
                        onToggleMultiSelect={onToggleMultiSelectMode}
                        onToggleSelect={
                          onToggleAllocationSelect
                            ? () => onToggleAllocationSelect(allocation.id)
                            : undefined
                        }
                        onTransfer={
                          onTransferAllocation
                            ? (personId) => onTransferAllocation(allocation, personId)
                            : undefined
                        }
                        onUpdate={(draft) => onUpdateAllocation(allocation, draft)}
                        selected={selectedAllocationIds?.has(allocation.id) ?? false}
                        transferPeople={transferCandidates}
                        weeklyCapacityHrs={person.weekly_capacity_hrs}
                      />
                    </div>
                  </div>
                );
              })}
            </div>
          ))}

          {project.is_active ? (
            <div className="planner-row planner-project-subrow planner-add-member-row">
              <button className="planner-row-label nested add-member" onClick={onAddPerson} type="button">
                <span className="plus">+</span> Add Person or Placeholder
              </button>
              <div className="planner-row-track">
                {candidatePeople.length > 0 ? (
                  <AllocationDragTimeline
                    candidatePeople={candidatePeople}
                    color={project.color}
                    dayDates={dayDates}
                    effortMode={effortMode}
                    isSaving={isSavingAllocation}
                    onSave={onCreateAllocation}
                  />
                ) : null}
              </div>
            </div>
          ) : null}
        </>
      ) : null}
    </div>
  );
}
