import { useLayoutEffect, useMemo, useRef, useState } from "react";
import type { TimelinePlanSegment, TimelineRange, TimelineRow } from "../../model/timelineTypes";
import {
  buildSequentialLinks,
  buildTimeTicks,
  buildTimelineSegments,
  TIMELINE_AXIS_HEIGHT,
  TIMELINE_BOTTOM_PADDING,
  TIMELINE_LABEL_WIDTH,
  TIMELINE_ROW_HEIGHT,
  timeToX,
  timelineHeight
} from "./tguTimelineLayout";
import { platformLabel } from "./tguTimelineMapper";
import { statusStyle } from "./tguStatus";

type TguTimelineProps = {
  rows: TimelineRow[];
  range: TimelineRange;
  selectedPlanId?: string;
  invalidRange?: boolean;
  onSelectPlan: (planId: string) => void;
};

export function TguTimeline({ rows, range, selectedPlanId, invalidRange, onSelectPlan }: TguTimelineProps) {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const [containerWidth, setContainerWidth] = useState(1200);
  const timelineWidth = Math.max(720, containerWidth - TIMELINE_LABEL_WIDTH - 28);
  const fullWidth = TIMELINE_LABEL_WIDTH + timelineWidth;
  const height = Math.max(260, timelineHeight(rows.length));
  const nowMs = Date.now();

  useLayoutEffect(() => {
    if (!containerRef.current) return;

    setContainerWidth(Math.floor(containerRef.current.getBoundingClientRect().width));

    const observer = new ResizeObserver(([entry]) => {
      setContainerWidth(Math.floor(entry.contentRect.width));
    });
    observer.observe(containerRef.current);
    return () => observer.disconnect();
  }, []);

  const segments = useMemo(
    () => buildTimelineSegments(rows, range, timelineWidth),
    [rows, range, timelineWidth]
  );
  const segmentByPlanId = useMemo(
    () => new Map(segments.map((segment) => [segment.plan.planId, segment])),
    [segments]
  );
  const links = useMemo(() => buildSequentialLinks(rows), [rows]);
  const ticks = useMemo(() => buildTimeTicks(range), [range]);
  const nowX =
    nowMs >= range.fromMs && nowMs <= range.toMs
      ? TIMELINE_LABEL_WIDTH + timeToX(nowMs, range, timelineWidth)
      : undefined;

  return (
    <div className="tgu-timeline" ref={containerRef}>
      {invalidRange ? (
        <div className="tgu-empty">Некорректный интервал: from должен быть меньше to.</div>
      ) : rows.length === 0 || segments.length === 0 ? (
        <div className="tgu-empty">Нет планов в выбранном интервале.</div>
      ) : (
      <svg className="tgu-timeline__svg" viewBox={`0 0 ${fullWidth} ${height}`} style={{ height }} role="img" aria-label="Timeline планов ТГУ">
        <defs>
          <marker id="tgu-arrow-head" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto">
            <path d="M0 0 L8 4 L0 8 z" fill="#8aa2a6" />
          </marker>
        </defs>

        <rect x="0" y="0" width={fullWidth} height={height} className="tgu-timeline__background" />
        <rect x="0" y="0" width={TIMELINE_LABEL_WIDTH} height={height} className="tgu-timeline__labels-background" />

        <line
          x1={TIMELINE_LABEL_WIDTH}
          x2={fullWidth}
          y1={TIMELINE_AXIS_HEIGHT}
          y2={TIMELINE_AXIS_HEIGHT}
          className="tgu-timeline__axis"
        />

        {ticks.map((tick) => {
          const x = TIMELINE_LABEL_WIDTH + timeToX(tick, range, timelineWidth);
          return (
            <g key={tick}>
              <line x1={x} x2={x} y1="0" y2={height - TIMELINE_BOTTOM_PADDING} className="tgu-timeline__grid" />
              <text x={x + 6} y="18" className="tgu-timeline__tick-date">
                {formatTickDate(tick)}
              </text>
              <text x={x + 6} y="34" className="tgu-timeline__tick-time">
                {formatTickTime(tick)}
              </text>
            </g>
          );
        })}

        {nowX !== undefined && (
          <g>
            <line x1={nowX} x2={nowX} y1="0" y2={height - TIMELINE_BOTTOM_PADDING} className="tgu-timeline__now" />
            <text x={nowX + 7} y="16" className="tgu-timeline__now-label">
              сейчас
            </text>
          </g>
        )}

        {rows.map((row, rowIndex) => {
          const y = TIMELINE_AXIS_HEIGHT + rowIndex * TIMELINE_ROW_HEIGHT;
          return (
            <g key={row.spacecraftId}>
              <rect
                x="0"
                y={y}
                width={fullWidth}
                height={TIMELINE_ROW_HEIGHT}
                className={rowIndex % 2 === 0 ? "tgu-timeline__row" : "tgu-timeline__row tgu-timeline__row--alt"}
              />
              <text x="16" y={y + 24} className="tgu-timeline__row-title">
                {platformLabel(row.platform, row.spacecraftId)}
              </text>
              <text x="16" y={y + 42} className="tgu-timeline__row-meta">
                NORAD {row.platform?.noradId || row.spacecraftId}
              </text>
            </g>
          );
        })}

        {links.map((link) => {
          const from = segmentByPlanId.get(link.fromPlanId);
          const to = segmentByPlanId.get(link.toPlanId);
          if (!from || !to) return null;
          return <TimelineArrow key={`${link.fromPlanId}-${link.toPlanId}`} from={from} to={to} />;
        })}

        {segments.map((segment) => {
          const y =
            TIMELINE_AXIS_HEIGHT +
            segment.rowIndex * TIMELINE_ROW_HEIGHT +
            TIMELINE_ROW_HEIGHT / 2 +
            segment.laneOffset;
          const x1 = TIMELINE_LABEL_WIDTH + segment.x;
          const x2 = TIMELINE_LABEL_WIDTH + segment.x + segment.width;
          const style = statusStyle(segment.plan.status);
          const selected = selectedPlanId === segment.plan.planId;
          const labelVisible = segment.width > 92;

          return (
            <g
              key={segment.plan.planId}
              className={`tgu-timeline-plan ${selected ? "is-selected" : ""}`}
              onClick={() => onSelectPlan(segment.plan.planId)}
            >
              <title>
                {segment.plan.planId} · {segment.plan.status} · {formatDateTime(segment.plan.startTime)} -{" "}
                {formatDateTime(segment.plan.endTime)}
              </title>
              {selected && <line x1={x1} x2={x2} y1={y} y2={y} className="tgu-timeline-plan__selection" />}
              <line
                x1={x1}
                x2={x2}
                y1={y}
                y2={y}
                className={`tgu-timeline-plan__bar ${style.className}`}
                stroke={style.color}
              />
              {labelVisible && (
                <text x={x1 + 10} y={y + 4} className="tgu-timeline-plan__label">
                  {segment.plan.kppId} · {segment.plan.status}
                </text>
              )}
            </g>
          );
        })}
      </svg>
      )}
    </div>
  );
}

function TimelineArrow({ from, to }: { from: TimelinePlanSegment; to: TimelinePlanSegment }) {
  const y1 = TIMELINE_AXIS_HEIGHT + from.rowIndex * TIMELINE_ROW_HEIGHT + TIMELINE_ROW_HEIGHT / 2 + from.laneOffset;
  const y2 = TIMELINE_AXIS_HEIGHT + to.rowIndex * TIMELINE_ROW_HEIGHT + TIMELINE_ROW_HEIGHT / 2 + to.laneOffset;
  const x1 = TIMELINE_LABEL_WIDTH + from.x + from.width + 4;
  const x2 = TIMELINE_LABEL_WIDTH + to.x - 6;
  const mid = x1 + Math.max(18, (x2 - x1) / 2);
  const path = x2 > x1
    ? `M ${x1} ${y1} C ${mid} ${y1}, ${mid} ${y2}, ${x2} ${y2}`
    : `M ${x1} ${y1} C ${x1 + 20} ${y1 - 18}, ${x2 - 20} ${y2 - 18}, ${x2} ${y2}`;

  return <path d={path} className="tgu-timeline__arrow" markerEnd="url(#tgu-arrow-head)" />;
}

function formatTickDate(ms: number): string {
  return new Date(ms).toLocaleDateString("ru-RU", { day: "2-digit", month: "2-digit" });
}

function formatTickTime(ms: number): string {
  return new Date(ms).toLocaleTimeString("ru-RU", { hour: "2-digit", minute: "2-digit" });
}

function formatDateTime(value: string): string {
  return new Date(value).toLocaleString("ru-RU");
}
