import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
  buildMilestoneTimeline,
  computeFullTimelineRange,
  milestoneHasTimelineDates,
  panPortfolioViewport,
  resolveTimelineInitialViewport,
  zoomPortfolioViewport,
  type PortfolioTaskGroup,
  type TimelineMilestoneInput,
  type TimelineRangeFallback,
} from '../../lib/milestoneTimeline';

/** focus: 선택 업무 3개월 | project: 프로젝트/해당 업무 전체 | portfolio: 분기 전체 */
export type TimelineViewMode = 'focus' | 'project' | 'portfolio';

interface MilestoneTimelineProps {
  milestones: TimelineMilestoneInput[];
  portfolioTasks?: PortfolioTaskGroup[];
  fallback?: TimelineRangeFallback;
  selectedId?: string | null;
  onSelect?: (id: string) => void;
  ownerTaskId?: string;
  title?: string;
  subtitle?: string;
  emptyMessage?: string;
  className?: string;
  hideUndatedBars?: boolean;
  variant?: 'project' | 'routine';
  viewMode?: TimelineViewMode;
  onViewModeChange?: (mode: TimelineViewMode) => void;
  focusTitle?: string;
  projectTitle?: string;
  portfolioTitle?: string;
  rowLabelHeader?: string;
}

const VARIANT_DEFAULTS = {
  project: {
    focusTitle: '업무별 타임라인',
    projectTitle: '프로젝트 전체 일정',
    portfolioTitle: '분기 전체 프로젝트',
    rowLabelHeader: '업무 일정',
    focusTab: '선택 업무',
    projectTab: '프로젝트',
    portfolioTab: '분기 전체',
  },
  routine: {
    focusTitle: '업무명별 타임라인',
    projectTitle: '상시 전체 일정',
    portfolioTitle: '분기 전체 상시업무',
    rowLabelHeader: '업무명',
    focusTab: '선택 업무',
    projectTab: '분류',
    portfolioTab: '분기 전체',
  },
} as const;

type PortfolioRow =
  | { kind: 'group'; taskId: string; title: string }
  | {
      kind: 'milestone';
      taskId: string;
      milestoneId: string;
      title: string;
      progress: number;
      segments: Array<{ id: string; leftPct: number; widthPct: number; progress: number }>;
      isCurrentTask: boolean;
    };

export function MilestoneTimeline({
  milestones,
  portfolioTasks,
  fallback = {},
  selectedId,
  onSelect,
  ownerTaskId,
  title,
  subtitle,
  emptyMessage = '기간을 설정한 단계만 표시됩니다.',
  hideUndatedBars = true,
  className = '',
  variant = 'project',
  viewMode = 'focus',
  onViewModeChange,
  focusTitle,
  projectTitle,
  portfolioTitle,
  rowLabelHeader,
}: MilestoneTimelineProps) {
  const defaults = VARIANT_DEFAULTS[variant];
  const isPortfolio = viewMode === 'portfolio';
  const isGantt = viewMode !== 'focus';
  const displayTitle =
    title ??
    (viewMode === 'portfolio'
      ? (portfolioTitle ?? defaults.portfolioTitle)
      : viewMode === 'project'
        ? (projectTitle ?? defaults.projectTitle)
        : (focusTitle ?? defaults.focusTitle));
  const labelHeader = rowLabelHeader ?? defaults.rowLabelHeader;

  const portfolioFlatMilestones = useMemo(() => {
    if (!portfolioTasks?.length) return [];
    return portfolioTasks.flatMap((t) => t.milestones);
  }, [portfolioTasks]);

  const chartMilestones = isPortfolio ? portfolioFlatMilestones : milestones;

  const dataRange = useMemo(
    () => computeFullTimelineRange(chartMilestones, fallback),
    [chartMilestones, fallback],
  );

  const [chartViewport, setChartViewport] = useState<{ start: Date; end: Date } | null>(null);

  useEffect(() => {
    if (!dataRange) {
      setChartViewport(null);
      return;
    }
    setChartViewport(resolveTimelineInitialViewport(viewMode, chartMilestones, fallback, selectedId));
  }, [
    viewMode,
    dataRange?.start.getTime(),
    dataRange?.end.getTime(),
    viewMode === 'focus' ? selectedId : undefined,
  ]);

  const model = useMemo(() => {
    if (!chartViewport) return null;
    return buildMilestoneTimeline(chartMilestones, fallback, {
      hideUndatedBars,
      focusQuarter: false,
      viewport: chartViewport,
      ganttBars: isGantt,
    });
  }, [chartMilestones, fallback, hideUndatedBars, isGantt, chartViewport]);

  const chartRef = useRef<HTMLDivElement>(null);
  const labelsScrollRef = useRef<HTMLDivElement>(null);
  const rowRefs = useRef<Map<string, HTMLDivElement>>(new Map());
  const dragRef = useRef<{ startX: number; viewport: { start: Date; end: Date } } | null>(null);
  const didPanRef = useRef(false);
  const [isPanning, setIsPanning] = useState(false);

  const rowGroups = useMemo(() => {
    if (!model) return [];
    const titleById = new Map(chartMilestones.map((m) => [m.id, m.title]));
    const groups: Array<{
      milestoneId: string;
      title: string;
      progress: number;
      segments: (typeof model.rows)[number][];
    }> = [];
    const indexByMilestone = new Map<string, number>();
    for (const row of model.rows) {
      const idx = indexByMilestone.get(row.milestoneId);
      if (idx === undefined) {
        indexByMilestone.set(row.milestoneId, groups.length);
        groups.push({
          milestoneId: row.milestoneId,
          title: titleById.get(row.milestoneId) ?? row.title,
          progress: row.progress,
          segments: [row],
        });
      } else {
        groups[idx].segments.push(row);
      }
    }
    return groups;
  }, [model, chartMilestones]);

  const rowGroupByMilestone = useMemo(() => {
    const map = new Map<string, (typeof rowGroups)[number]>();
    for (const g of rowGroups) map.set(g.milestoneId, g);
    return map;
  }, [rowGroups]);

  const portfolioRows = useMemo((): PortfolioRow[] => {
    if (!isPortfolio || !portfolioTasks) return [];
    const rows: PortfolioRow[] = [];
    for (const task of portfolioTasks) {
      const dated = task.milestones.filter((m) =>
        hideUndatedBars ? milestoneHasTimelineDates(m) : true,
      );
      if (dated.length === 0) continue;
      rows.push({ kind: 'group', taskId: task.id, title: task.title });
      for (const m of dated) {
        const group = rowGroupByMilestone.get(m.id);
        rows.push({
          kind: 'milestone',
          taskId: task.id,
          milestoneId: m.id,
          title: m.title,
          progress: group?.progress ?? m.progress ?? 0,
          segments: group?.segments ?? [],
          isCurrentTask: task.id === ownerTaskId,
        });
      }
    }
    return rows;
  }, [isPortfolio, portfolioTasks, rowGroupByMilestone, hideUndatedBars, ownerTaskId]);

  const projectRowGroups = useMemo(() => {
    if (isPortfolio) return [];
    return rowGroups;
  }, [isPortfolio, rowGroups]);

  const syncScroll = (source: 'labels' | 'chart') => {
    const labels = labelsScrollRef.current;
    const chart = chartRef.current;
    if (!labels || !chart) return;
    if (source === 'labels') chart.scrollTop = labels.scrollTop;
    else labels.scrollTop = chart.scrollTop;
  };

  const handleChartPanStart = (e: React.MouseEvent) => {
    if (!chartViewport || !dataRange || e.button !== 0) return;
    e.preventDefault();
    didPanRef.current = false;
    dragRef.current = { startX: e.clientX, viewport: chartViewport };
    setIsPanning(true);
  };

  const handleChartPanMove = useCallback(
    (e: MouseEvent) => {
      const drag = dragRef.current;
      if (!drag || !dataRange || !chartRef.current) return;
      if (Math.abs(e.clientX - drag.startX) > 4) didPanRef.current = true;
      const chartWidth = chartRef.current.clientWidth;
      if (chartWidth <= 0) return;
      const windowMs = drag.viewport.end.getTime() - drag.viewport.start.getTime();
      const deltaMs = -((e.clientX - drag.startX) / chartWidth) * windowMs;
      setChartViewport(panPortfolioViewport(drag.viewport, dataRange, deltaMs));
    },
    [dataRange],
  );

  const handleChartPanEnd = useCallback(() => {
    dragRef.current = null;
    setIsPanning(false);
  }, []);

  useEffect(() => {
    if (!isPanning) return;
    window.addEventListener('mousemove', handleChartPanMove);
    window.addEventListener('mouseup', handleChartPanEnd);
    return () => {
      window.removeEventListener('mousemove', handleChartPanMove);
      window.removeEventListener('mouseup', handleChartPanEnd);
    };
  }, [isPanning, handleChartPanMove, handleChartPanEnd]);

  useEffect(() => {
    if (!chartViewport || !dataRange) return;
    const el = chartRef.current;
    if (!el) return;
    const onWheel = (e: WheelEvent) => {
      e.preventDefault();
      const rect = el.getBoundingClientRect();
      const anchorPct = rect.width > 0 ? (e.clientX - rect.left) / rect.width : 0.5;
      const factor = e.deltaY > 0 ? 1.12 : 0.88;
      setChartViewport(zoomPortfolioViewport(chartViewport, dataRange, factor, anchorPct));
    };
    el.addEventListener('wheel', onWheel, { passive: false });
    return () => el.removeEventListener('wheel', onWheel);
  }, [chartViewport, dataRange]);

  useEffect(() => {
    if (!selectedId || !isGantt || isPortfolio) return;
    const row = rowRefs.current.get(selectedId);
    const chart = chartRef.current;
    if (!row || !chart) return;
    const rowRect = row.getBoundingClientRect();
    const chartRect = chart.getBoundingClientRect();
    if (rowRect.top >= chartRect.top && rowRect.bottom <= chartRect.bottom) return;
    const delta =
      rowRect.top < chartRect.top
        ? rowRect.top - chartRect.top
        : rowRect.bottom - chartRect.bottom;
    chart.scrollBy({ top: delta, behavior: 'smooth' });
  }, [selectedId, model?.rows.length, viewMode, isGantt, isPortfolio]);

  useEffect(() => {
    setIsPanning(false);
    dragRef.current = null;
    didPanRef.current = false;
  }, [viewMode]);

  const handleRowSelect = (milestoneId: string, taskId: string) => {
    if (didPanRef.current) return;
    if (isPortfolio && ownerTaskId && taskId !== ownerTaskId) return;
    onSelect?.(milestoneId);
  };

  const renderBar = (
    group: {
      milestoneId: string;
      title: string;
      progress: number;
      segments: Array<{ id: string; leftPct: number; widthPct: number; progress: number }>;
    },
    isSelected: boolean,
    taskId: string,
    showGanttBar: boolean,
  ) =>
    group.segments.map((row) => (
      <button
        key={row.id}
        type="button"
        className={`milestone-timeline__bar ${isSelected ? 'is-selected' : ''} ${showGanttBar ? 'is-gantt' : ''}`}
        style={{ left: `${row.leftPct}%`, width: `${row.widthPct}%` }}
        aria-label={group.title}
        title={group.title}
        onClick={() => handleRowSelect(group.milestoneId, taskId)}
      >
        <span className="milestone-timeline__bar-track" />
        <span className="milestone-timeline__bar-fill" style={{ width: `${row.progress}%` }} />
        {showGanttBar && group.progress > 0 && (
          <span className="milestone-timeline__bar-progress">{group.progress}%</span>
        )}
      </button>
    ));

  const renderTicks = () => (
    <div className="milestone-timeline__ticks" aria-hidden="true">
      {model!.ticks.map((tick) => (
        <span
          key={`${tick.label}-${tick.leftPct}`}
          className={`milestone-timeline__tick${tick.isToday ? ' is-today' : ''}`}
          style={{ left: `${tick.leftPct}%` }}
          title={tick.isToday ? `오늘 (${tick.label})` : undefined}
        >
          <span className="milestone-timeline__tick-label">{tick.label}</span>
        </span>
      ))}
    </div>
  );

  const renderGrid = (includeToday = true) => (
    <div className="milestone-timeline__grid" aria-hidden="true">
      {model!.ticks.map((tick) => (
        <span
          key={`grid-${tick.label}-${tick.leftPct}`}
          className="milestone-timeline__grid-line"
          style={{ left: `${tick.leftPct}%` }}
        />
      ))}
      {includeToday && model!.todayLeftPct != null && (
        <span
          className="milestone-timeline__today-line"
          style={{ left: `${model!.todayLeftPct}%` }}
        />
      )}
    </div>
  );

  const rowCount = isPortfolio ? portfolioRows.length : projectRowGroups.length;
  const chartPannableClass = `milestone-timeline__chart milestone-timeline__chart--pannable${isPanning ? ' is-panning' : ''}`;

  const renderChartHead = () => (
    <div className="milestone-timeline__chart-head">
      {renderTicks()}
      <span className="milestone-timeline__viewport-range">
        {model!.rangeStartLabel}~{model!.rangeEndLabel}
      </span>
    </div>
  );

  const renderPanHint = () => (
    <p className="milestone-timeline__pan-hint">
      드래그: 기간 이동 · 휠: 확대/축소 · {model!.rangeStartLabel}~{model!.rangeEndLabel}
    </p>
  );

  return (
    <footer
      className={`milestone-timeline ${isGantt ? 'milestone-timeline--gantt' : ''} ${isPortfolio ? 'milestone-timeline--portfolio' : ''} ${className}`.trim()}
      style={rowCount > 0 ? ({ '--mt-row-count': String(rowCount) } as React.CSSProperties) : undefined}
    >
      <div className="milestone-timeline__head">
        <span className="milestone-timeline__title">{displayTitle}</span>
        {subtitle && <span className="milestone-timeline__subtitle truncate">{subtitle}</span>}
        {onViewModeChange && (
          <div className="milestone-timeline__view-toggle" role="tablist" aria-label="타임라인 보기">
            <button
              type="button"
              role="tab"
              aria-selected={viewMode === 'focus'}
              className={viewMode === 'focus' ? 'is-active' : ''}
              onClick={() => onViewModeChange('focus')}
            >
              {defaults.focusTab}
            </button>
            <button
              type="button"
              role="tab"
              aria-selected={viewMode === 'project'}
              className={viewMode === 'project' ? 'is-active' : ''}
              onClick={() => onViewModeChange('project')}
            >
              {defaults.projectTab}
            </button>
            <button
              type="button"
              role="tab"
              aria-selected={viewMode === 'portfolio'}
              className={viewMode === 'portfolio' ? 'is-active' : ''}
              onClick={() => onViewModeChange('portfolio')}
            >
              {defaults.portfolioTab}
            </button>
          </div>
        )}
      </div>

      {!model ? (
        <p className="milestone-timeline__empty">{emptyMessage}</p>
      ) : isPortfolio ? (
        <div className="milestone-timeline__portfolio-layout">
          <div className="milestone-timeline__portfolio-head">
            <div className="milestone-timeline__row-labels-head">{labelHeader}</div>
            <div className="milestone-timeline__portfolio-chart-head">
              <div className="milestone-timeline__body milestone-timeline__body--ticks-only">
                {renderTicks()}
              </div>
              {model && (
                <span className="milestone-timeline__viewport-range">
                  {model.rangeStartLabel}~{model.rangeEndLabel}
                </span>
              )}
            </div>
          </div>

          <div className="milestone-timeline__portfolio-scroll">
            <div
              className="milestone-timeline__row-labels-body"
              ref={labelsScrollRef}
              onScroll={() => syncScroll('labels')}
            >
              {portfolioRows.map((row) =>
                row.kind === 'group' ? (
                  <div
                    key={`group-${row.taskId}`}
                    className="milestone-timeline__group-label"
                    title={row.title}
                  >
                    {row.title}
                  </div>
                ) : (
                  <button
                    key={row.milestoneId}
                    type="button"
                    className={`milestone-timeline__row-label milestone-timeline__row-label--child${row.milestoneId === selectedId && row.isCurrentTask ? ' is-selected' : ''}${row.isCurrentTask ? ' is-current-task' : ' is-other-task'}`}
                    onClick={() => handleRowSelect(row.milestoneId, row.taskId)}
                    title={row.title}
                  >
                    {row.title}
                  </button>
                ),
              )}
            </div>

            <div
              className={chartPannableClass}
              ref={chartRef}
              onMouseDown={handleChartPanStart}
              onScroll={() => syncScroll('chart')}
            >
              {renderGrid()}
              <div className="milestone-timeline__rows">
                {portfolioRows.map((row) =>
                  row.kind === 'group' ? (
                    <div key={`g-${row.taskId}`} className="milestone-timeline__row milestone-timeline__row--group" />
                  ) : (
                    <div
                      key={row.milestoneId}
                      className={`milestone-timeline__row${row.isCurrentTask ? ' is-current-task' : ' is-other-task'}`}
                    >
                      {renderBar(
                        row,
                        row.milestoneId === selectedId && row.isCurrentTask,
                        row.taskId,
                        true,
                      )}
                    </div>
                  ),
                )}
              </div>
            </div>
          </div>

          {renderPanHint()}
        </div>
      ) : isGantt ? (
        <>
          <div className="milestone-timeline__gantt-layout">
            <div className="milestone-timeline__row-labels">
              <div className="milestone-timeline__row-labels-head">{labelHeader}</div>
              <div className="milestone-timeline__row-labels-body">
                {projectRowGroups.map((group) => (
                  <button
                    key={group.milestoneId}
                    type="button"
                    className={`milestone-timeline__row-label${group.milestoneId === selectedId ? ' is-selected' : ''}`}
                    onClick={() => handleRowSelect(group.milestoneId, ownerTaskId ?? '')}
                    title={group.title}
                  >
                    {group.title}
                  </button>
                ))}
              </div>
            </div>
            <div className="milestone-timeline__body">
              {renderChartHead()}
              <div
                className={chartPannableClass}
                ref={chartRef}
                onMouseDown={handleChartPanStart}
              >
                {renderGrid()}
                <div className="milestone-timeline__rows">
                  {projectRowGroups.map((group) => (
                    <div
                      key={group.milestoneId}
                      className="milestone-timeline__row"
                      ref={(el) => {
                        if (el) rowRefs.current.set(group.milestoneId, el);
                        else rowRefs.current.delete(group.milestoneId);
                      }}
                    >
                      {renderBar(group, group.milestoneId === selectedId, ownerTaskId ?? '', true)}
                    </div>
                  ))}
                </div>
              </div>
            </div>
          </div>
          {renderPanHint()}
        </>
      ) : (
        <div className="milestone-timeline__focus-layout">
          {renderChartHead()}
          <div
            className={chartPannableClass}
            ref={chartRef}
            onMouseDown={handleChartPanStart}
          >
            {renderGrid()}
            <div className="milestone-timeline__rows">
              {projectRowGroups.map((group) => (
                <div key={group.milestoneId} className="milestone-timeline__row">
                  {renderBar(group, group.milestoneId === selectedId, ownerTaskId ?? '', false)}
                </div>
              ))}
            </div>
          </div>
          {renderPanHint()}
        </div>
      )}
    </footer>
  );
}
