import { positionToZone } from "../../helpers/zones";
import { cellPopoverRegistry } from "../../registries/cell_popovers_registry";
import { SpreadsheetStore } from "../../stores/spreadsheet_store";
import { ViewportsStore } from "../../stores/viewports_store";
import {
  CellPopoverType,
  ClosedCellPopover,
  OpenCellPopover,
  PositionedCellPopoverComponent,
} from "../../types/cell_popovers";
import { Command } from "../../types/commands";
import { CellPosition, Position } from "../../types/misc";
import { Rect } from "../../types/rendering";
import { DelayedHoveredCellStore } from "../grid/delayed_hovered_cell_store";

export class CellPopoverStore extends SpreadsheetStore {
  mutators = ["open", "close"] as const;

  private persistentPopover?: CellPosition & { type: CellPopoverType };

  protected hoveredCell = this.get(DelayedHoveredCellStore);
  private viewStore = this.get(ViewportsStore);

  handle(cmd: Command) {
    switch (cmd.type) {
      case "ACTIVATE_SHEET":
        this.close();
    }
  }

  open({ col, row }: Position, type: CellPopoverType): void {
    const sheetId = this.viewStore.displayedSheetId;
    if (!cellPopoverRegistry.contains(type)) {
      return;
    }
    this.persistentPopover = { col, row, sheetId, type };
  }

  close() {
    if (!this.persistentPopover) {
      return "noStateChange";
    }
    this.persistentPopover = undefined;
    return;
  }

  get persistentCellPopover(): OpenCellPopover | ClosedCellPopover {
    return (
      (this.persistentPopover && { isOpen: true, ...this.persistentPopover }) || { isOpen: false }
    );
  }

  get isOpen() {
    return this.persistentPopover !== undefined;
  }

  get cellPopover(): ClosedCellPopover | PositionedCellPopoverComponent {
    const sheetId = this.viewStore.displayedSheetId;

    if (
      this.persistentPopover &&
      this.persistentPopover.sheetId === sheetId &&
      this.viewStore.viewports.isVisibleInViewport(this.persistentPopover)
    ) {
      const position = this.getters.getMainCellPosition(this.persistentPopover);
      const popover = cellPopoverRegistry
        .get(this.persistentPopover.type)
        .onOpen?.(position, this.getters);
      return !popover?.isOpen
        ? { isOpen: false }
        : {
            ...popover,
            anchorRect: this.computePopoverAnchorRect(this.persistentPopover),
          };
    }
    const { col, row } = this.hoveredCell;
    if (
      col === undefined ||
      row === undefined ||
      !this.viewStore.viewports.isVisibleInViewport({ sheetId, col, row })
    ) {
      return { isOpen: false };
    }
    const position = this.getters.getMainCellPosition({ sheetId, col, row });
    const popover = cellPopoverRegistry
      .getAll()
      .map((matcher) => matcher.onHover?.(position, this.getters))
      .find((popover) => popover?.isOpen);
    return !popover?.isOpen
      ? { isOpen: false }
      : {
          ...popover,
          anchorRect: this.computePopoverAnchorRect(position),
        };
  }

  private computePopoverAnchorRect({ col, row }: Position): Rect {
    const sheetId = this.viewStore.displayedSheetId;
    const merge = this.getters.getMerge({ sheetId, col, row });
    if (merge) {
      return this.viewStore.viewports.getVisibleRect(sheetId, merge);
    }
    return this.viewStore.viewports.getVisibleRect(sheetId, positionToZone({ col, row }));
  }
}
