import { onWillStart, onWillUpdateProps, useProps } from "@odoo/owl";
import { getCarouselLayout } from "../../helpers/carousel_helpers";
import { isDefined } from "../../helpers/misc";
import { Component } from "../../owl3_compatibility_layer";
import { useLocalStore } from "../../store_engine/store_hooks";
import { RendererStore } from "../../stores/renderer_store";
import { PropsOf } from "../../types/props_of";
import { GridRenderingContext } from "../../types/rendering";
import { SpreadsheetChildEnv } from "../../types/spreadsheet_env";
import { Store } from "../../types/store_engine";
import { useGridDrawing } from "../helpers/draw_grid_hook";
import { types } from "../props_validation";
import { CarouselDataViewPrint } from "./carousel_data_view_print";
import { FigureRendererStore } from "./figure_renderer_store";

export class StandaloneGridCanvas extends Component<SpreadsheetChildEnv> {
  static template = "o-spreadsheet-StandaloneGridCanvas";
  static components = { CarouselDataViewPrint };

  protected props = useProps({
    sheetId: types.UID(),
    zone: types.Zone(),
    renderingCtx: types.object<Omit<GridRenderingContext, "ctx" | "thinLineWidth">>(),
    canvas: types.object<HTMLCanvasElement>(),
  });

  rendererStore!: Store<RendererStore>;
  figureRendererStore!: Store<FigureRendererStore>;

  setup() {
    this.rendererStore = useLocalStore(RendererStore, ["Background", "Chart"]);
    this.figureRendererStore = useLocalStore(FigureRendererStore, this.rendererStore);
    useGridDrawing({
      canvasRef: () => this.props.canvas,
      renderingCtx: () => this.props.renderingCtx,
      rendererStore: this.rendererStore,
      changeCanvasSizeOnZoom: true,
    });
    onWillStart(async () => await this.loadImages(this.props));
    onWillUpdateProps(
      async (nextProps: PropsOf<StandaloneGridCanvas>) => await this.loadImages(nextProps)
    );
  }

  private async loadImages(props: PropsOf<StandaloneGridCanvas>) {
    const imagePaths = props.renderingCtx.viewports
      .getVisibleFigures(props.sheetId)
      .filter((figure) => figure.tag === "image")
      .map((figure) => this.env.model.getters.getImagePath(figure.id))
      .filter((path) => path && !this.figureRendererStore.loadedImages[path]);

    await Promise.all(
      imagePaths.map(async (path) => {
        const response = await fetch(path);
        const blob = await response.blob();
        this.figureRendererStore.addLoadedImage(path, await createImageBitmap(blob));
      })
    );
  }

  get carouselDataViews(): PropsOf<CarouselDataViewPrint>[] {
    const { sheetId, viewports } = this.props.renderingCtx;
    return viewports
      .getVisibleFigures(sheetId)
      .filter((figure) => figure.tag === "carousel")
      .map((figure) => {
        const carouselItem = this.env.model.getters.getSelectedCarouselItem(figure.id);
        if (carouselItem?.type !== "carouselDataView" || !carouselItem.range) {
          return undefined;
        }

        const carousel = this.env.model.getters.getCarousel(figure.id);
        const scroll = viewports.getViewportOffset(sheetId);
        const { x, y, width, height } = figure;
        const mainRect = { x: x - scroll.x, y: y - scroll.y, width, height };
        const layout = getCarouselLayout(mainRect, carousel, carouselItem);

        return {
          range: carouselItem.range,
          columnWeights: carouselItem.columnWeights,
          rect: layout.contentRect,
          rendererStore: this.rendererStore,
        };
      })
      .filter(isDefined);
  }
}
