import { useCallback, useEffect, useMemo, useState } from "react";
import { createRequest, deleteRequest, fetchRequestsForMap } from "../../api/requestApi";
import { fetchStations, type StationDto } from "../../api/stationsApi";
import type { RequestMapItem } from "../../model/requestTypes";
import type { TguPlatformUi, TimelineRange } from "../../model/timelineTypes";
import { buildTgu2DMapScene } from "../tgu-map-2d/Tgu2DMapLayers";
import { Tgu2DMapView } from "../tgu-map-2d/Tgu2DMapView";
import type { RequestAtPoint } from "./RequestDetailsPanel";
import type { Tgu2DMapSelection } from "../tgu-map-2d/model/mapSelectionTypes";
import type { GeoPoint, MapPolygon } from "../tgu-map-2d/model/mapTypes";
import { generateUuid } from "../../utils/uuid";
import { parseLocal, toLocalInputValue, toUtcIso } from "../../utils/localTime";
import { DateTime24Field } from "../../components/timeFields";
import { RequestCreatePanel, type RequestFormSubmit } from "./RequestCreatePanel";
import { RequestDetailsPanel } from "./RequestDetailsPanel";
import { polygonToWkt } from "./requestGeometry";

type TguRequestsTabProps = {
  range: TimelineRange;
  invalidRange: boolean;
  platforms: TguPlatformUi[];
};

type RequestsLoadState = {
  fromValue: string;
  toValue: string;
  items: RequestMapItem[];
  loading: boolean;
  loadedCount: number;
  totalItems: number;
  truncated: boolean;
  error?: string;
  loaded: boolean;
};

type PanelMode = "none" | "details" | "create";

function buildInitialLoadState(range: TimelineRange): RequestsLoadState {
  return {
    fromValue: toLocalInputValue(range.fromMs),
    toValue: toLocalInputValue(range.toMs),
    items: [],
    loading: false,
    loadedCount: 0,
    totalItems: 0,
    truncated: false,
    loaded: false
  };
}

export function TguRequestsTab({ range, invalidRange, platforms }: TguRequestsTabProps) {
  const [requestsState, setRequestsState] = useState<RequestsLoadState>(() => buildInitialLoadState(range));
  const [stations, setStations] = useState<StationDto[]>([]);
  const [showStations, setShowStations] = useState(true);
  const [redrawToken, setRedrawToken] = useState(0);

  const [panelMode, setPanelMode] = useState<PanelMode>("none");
  const [requestsAtPoint, setRequestsAtPoint] = useState<RequestAtPoint[]>([]);
  const [selectedRequestPolygonId, setSelectedRequestPolygonId] = useState<string | undefined>();
  const [hoveredRequestPolygonId, setHoveredRequestPolygonId] = useState<string | undefined>();

  const [draftPolygon, setDraftPolygon] = useState<GeoPoint[]>([]);
  const [drawing, setDrawing] = useState(false);
  const [creating, setCreating] = useState(false);
  const [createError, setCreateError] = useState<string>();

  const [deleting, setDeleting] = useState(false);
  const [deleteError, setDeleteError] = useState<string>();
  const [notice, setNotice] = useState<string>();

  useEffect(() => {
    fetchStations()
      .then((items) => setStations(items))
      .catch(() => setStations([]));
  }, []);

  const loadRequests = useCallback(async (fromValue: string, toValue: string) => {
    const fromMs = parseLocal(fromValue);
    const toMs = parseLocal(toValue);
    if (!Number.isFinite(fromMs) || !Number.isFinite(toMs) || fromMs >= toMs) return;

    setRequestsState((current) => ({ ...current, loading: true, error: undefined, loadedCount: 0 }));
    try {
      const result = await fetchRequestsForMap(
        { endFrom: toUtcIso(fromMs), beginTo: toUtcIso(toMs) },
        (loaded, total) => setRequestsState((current) => ({ ...current, loadedCount: loaded, totalItems: total }))
      );
      setRequestsState((current) => ({
        ...current,
        items: result.items,
        loadedCount: result.items.length,
        totalItems: result.totalItems,
        truncated: result.truncated,
        loading: false,
        loaded: true
      }));
    } catch (error) {
      setRequestsState((current) => ({
        ...current,
        loading: false,
        error: error instanceof Error ? error.message : "Не удалось загрузить заявки."
      }));
    }
  }, []);

  useEffect(() => {
    setRequestsState(buildInitialLoadState(range));
  }, [range]);

  const applyRange = useCallback(() => {
    void loadRequests(requestsState.fromValue, requestsState.toValue);
  }, [loadRequests, requestsState.fromValue, requestsState.toValue]);

  const scene = useMemo(
    () =>
      buildTgu2DMapScene({
        range,
        platforms,
        requestItems: requestsState.items,
        stationItems: showStations ? stations : []
      }),
    [range, platforms, requestsState.items, showStations, stations]
  );

  const layers = useMemo(
    () => ({ tracks: false, swath: false, planWorks: false, complexPlan: false, heatmap: false, stations: showStations, spacecraftMarkers: false, requests: true }),
    [showStations]
  );

  const closeAll = useCallback(() => {
    setRequestsAtPoint([]);
    setSelectedRequestPolygonId(undefined);
    setHoveredRequestPolygonId(undefined);
    setDeleteError(undefined);
  }, []);

  const handleRequestsAtPoint = useCallback(
    (polygons: MapPolygon[]) => {
      if (panelMode === "create") return;
      if (polygons.length === 0) {
        closeAll();
        setPanelMode("none");
        return;
      }
      const joined = polygons.flatMap((polygon) => {
        const item = requestsState.items.find((r) => r.id === polygon.requestId);
        return item ? [{ polygon, item }] : [];
      });
      setRequestsAtPoint(joined);
      setSelectedRequestPolygonId(joined.length === 1 ? joined[0].polygon.id : undefined);
      setHoveredRequestPolygonId(undefined);
      setDeleteError(undefined);
      setPanelMode(joined.length > 0 ? "details" : "none");
    },
    [panelMode, requestsState.items, closeAll]
  );

  // Детали заявок открываются через onRequestsAtPoint. onObjectSelect карта
  // вызывает с undefined одновременно с onRequestsAtPoint, поэтому здесь no-op,
  // чтобы не затирать только что открытую панель (станции/пустой клик уже
  // закрывают панель через onRequestsAtPoint([])).
  const handleObjectSelect = useCallback((_selection?: Tgu2DMapSelection) => {}, []);

  const startCreate = useCallback(() => {
    closeAll();
    setDraftPolygon([]);
    setDrawing(true);
    setCreateError(undefined);
    setNotice(undefined);
    setPanelMode("create");
  }, [closeAll]);

  const cancelCreate = useCallback(() => {
    setDraftPolygon([]);
    setDrawing(false);
    setCreateError(undefined);
    setPanelMode("none");
  }, []);

  const handleDrawAddPoint = useCallback(
    (point: GeoPoint) => {
      if (panelMode !== "create" || !drawing) return;
      setDraftPolygon((current) => [...current, point]);
    },
    [panelMode, drawing]
  );

  const submitCreate = useCallback(
    async (form: RequestFormSubmit) => {
      let geometry: string;
      try {
        geometry = polygonToWkt(draftPolygon);
      } catch (error) {
        setCreateError(error instanceof Error ? error.message : "Некорректная геометрия.");
        return;
      }

      setCreating(true);
      setCreateError(undefined);
      try {
        const id = generateUuid();
        await createRequest({
          id,
          name: form.name,
          geometry,
          importance: form.importance,
          beginDateTime: toUtcIso(parseLocal(form.beginDateTime)),
          endDateTime: toUtcIso(parseLocal(form.endDateTime)),
          kpp: form.kpp,
          highPriorityTransmit: form.highPriorityTransmit,
          optics: form.optics,
          rsa: form.rsa
        });
        setDraftPolygon([]);
        setDrawing(false);
        setPanelMode("none");
        setNotice(`Заявка «${form.name}» создана.`);
        void loadRequests(requestsState.fromValue, requestsState.toValue);
      } catch (error) {
        setCreateError(error instanceof Error ? error.message : "Не удалось создать заявку.");
      } finally {
        setCreating(false);
      }
    },
    [draftPolygon, loadRequests, requestsState.fromValue, requestsState.toValue]
  );

  const handleDelete = useCallback(
    async (requestId: string) => {
      setDeleting(true);
      setDeleteError(undefined);
      try {
        await deleteRequest(requestId);
        closeAll();
        setPanelMode("none");
        setNotice("Заявка удалена.");
        void loadRequests(requestsState.fromValue, requestsState.toValue);
      } catch (error) {
        setDeleteError(error instanceof Error ? error.message : "Не удалось удалить заявку.");
      } finally {
        setDeleting(false);
      }
    },
    [closeAll, loadRequests, requestsState.fromValue, requestsState.toValue]
  );

  const fromMs = parseLocal(requestsState.fromValue);
  const toMs = parseLocal(requestsState.toValue);
  const rangeInvalid = !Number.isFinite(fromMs) || !Number.isFinite(toMs) || fromMs >= toMs;

  const hasPanel = panelMode !== "none";

  return (
    <main className="tgu-map-workspace">
      <div className="tgu-map-toolbar">
        <div>
          <div className="tgu-map-toolbar__title">Заявки</div>
          <div className="tgu-map-toolbar__subtitle">
            {requestsState.loaded ? `Загружено: ${requestsState.items.length}` : "Заявки не загружены"}
          </div>
        </div>
        <div className="tgu-map-toolbar__toggles">
          <button className="is-active" type="button" disabled>
            Заявки на съёмку
          </button>
          <button className={showStations ? "is-active" : ""} type="button" onClick={() => setShowStations((v) => !v)}>
            Станции
          </button>
        </div>
        <button
          className="tgu-button tgu-button--primary"
          type="button"
          onClick={startCreate}
          disabled={panelMode === "create"}
        >
          + Создать заявку
        </button>
        <button className="tgu-button" type="button" onClick={() => setRedrawToken((v) => v + 1)}>
          Перерисовать
        </button>
      </div>

      <div className={`tgu-map-content${hasPanel ? " has-side-panel" : ""}`}>
        <aside className="tgu-map-panel">
          <div className="tgu-panel-heading">
            <span>Заявки за интервал</span>
          </div>
          <div className="tgu-map-panel__section">
            <div className="tgu-map-requests-filter">
              <label className="tgu-field">
                <span>С</span>
                <DateTime24Field
                  value={requestsState.fromValue}
                  onChange={(value) => setRequestsState((cur) => ({ ...cur, fromValue: value }))}
                />
              </label>
              <label className="tgu-field">
                <span>По</span>
                <DateTime24Field
                  value={requestsState.toValue}
                  onChange={(value) => setRequestsState((cur) => ({ ...cur, toValue: value }))}
                />
              </label>
              <div className="tgu-map-requests-filter__actions">
                <button
                  className="tgu-button tgu-button--primary tgu-button--sm"
                  type="button"
                  onClick={applyRange}
                  disabled={requestsState.loading || rangeInvalid}
                >
                  {requestsState.loading ? "Загрузка..." : "Загрузить"}
                </button>
              </div>
              {requestsState.error && (
                <div className="tgu-alert tgu-alert--danger tgu-alert--compact">{requestsState.error}</div>
              )}
              {requestsState.loading && requestsState.totalItems > 0 && (
                <div className="tgu-map-requests-filter__status">
                  Загрузка: {requestsState.loadedCount} / {requestsState.totalItems}...
                </div>
              )}
              {requestsState.loaded && !requestsState.error && (
                <div className="tgu-map-requests-filter__status">
                  {requestsState.items.length === 0
                    ? "Заявок не найдено."
                    : `Загружено: ${requestsState.items.length} из ${requestsState.totalItems}`}
                  {requestsState.truncated && (
                    <span className="tgu-map-requests-filter__truncated"> (показаны первые 5000 — уточните интервал)</span>
                  )}
                </div>
              )}
              <div className="tgu-map-requests-legend">
                <span><i className="req-optics" />OPTICS</span>
                <span><i className="req-rsa" />RSA</span>
                <span><i className="req-combined" />COMBINED</span>
              </div>
            </div>
          </div>
          {notice && (
            <div className="tgu-map-panel__section">
              <div className="tgu-alert tgu-alert--success tgu-alert--compact">{notice}</div>
            </div>
          )}
          <div className="tgu-map-panel__section">
            <div className="tgu-map-panel__label">Создание заявки</div>
            <div className="tgu-map-panel__value">
              Нажмите «+ Создать заявку», затем нарисуйте полигон на карте кликами и заполните параметры справа.
            </div>
          </div>
        </aside>

        <section className="tgu-map-stage">
          {invalidRange && <div className="tgu-map-overlay">Некорректный интервал: from должен быть меньше to.</div>}
          {panelMode === "create" && drawing && (
            <div className="tgu-map-overlay tgu-map-overlay--hint">
              Кликайте по карте, чтобы добавить вершины полигона. Нажмите «Завершить» (≥3 вершин).
            </div>
          )}
          <Tgu2DMapView
            scene={scene}
            layers={layers}
            redrawToken={redrawToken}
            onObjectSelect={handleObjectSelect}
            onRequestsAtPoint={handleRequestsAtPoint}
            hoveredRequestPolygonId={hoveredRequestPolygonId}
            selectedRequestPolygonId={selectedRequestPolygonId}
            drawMode={panelMode === "create"}
            draftPolygon={draftPolygon}
            onDrawAddPoint={handleDrawAddPoint}
          />
        </section>

        {panelMode === "details" && (
          <RequestDetailsPanel
            requests={requestsAtPoint}
            selectedPolygonId={selectedRequestPolygonId}
            deleting={deleting}
            deleteError={deleteError}
            onHover={setHoveredRequestPolygonId}
            onSelect={setSelectedRequestPolygonId}
            onDelete={handleDelete}
            onClose={() => {
              closeAll();
              setPanelMode("none");
            }}
          />
        )}

        {panelMode === "create" && (
          <RequestCreatePanel
            vertexCount={draftPolygon.length}
            drawing={drawing}
            defaultBegin={requestsState.fromValue}
            defaultEnd={requestsState.toValue}
            submitting={creating}
            error={createError}
            onUndoPoint={() => setDraftPolygon((cur) => cur.slice(0, -1))}
            onClear={() => setDraftPolygon([])}
            onFinishDrawing={() => setDrawing(false)}
            onRestartDrawing={() => {
              setDraftPolygon([]);
              setDrawing(true);
            }}
            onSubmit={submitCreate}
            onCancel={cancelCreate}
          />
        )}
      </div>
    </main>
  );
}
