import * as Pixi from "pixi.js";
import { RenderedChunkConstants } from "./ChunkComponent";
import { UpdaterGeneratorType2 } from "../../lib/util/updaterGenerator";
import { GameState, PointNodeGen, PointNodeRef, ResourceModifier, ResourceType } from "../../data/GameState";
import { Vector2 } from "../../lib/util/geometry/vector2";
import { PixiPointFrom } from "../../lib/pixi/pixify";
import { multiplyColor } from "../../lib/util/misc";
import { TooltippableAreaComponent } from "./TooltippableAreaComponent";
import { engageLifecycle, LifecycleHandlerBase } from "./LifecycleHandler";
import { selectOrReselectNode } from "../../game/OnSelectOrReselectNode";
import { RootComponentState } from "./RootComponent";

type Props = {
  delta: number,
  args: {
    pointNodeTexture: Pixi.Texture,
    markForceUpdate: (childInstance: any) => void,
  },
  selfPointNodeRef: PointNodeRef,
  updaters: UpdaterGeneratorType2<GameState>,
  tooltipUpdaters: UpdaterGeneratorType2<RootComponentState>['tooltip'],
  position: Vector2,
  pointNodeGen: PointNodeGen,
  isSelected: boolean,
  isAllocated: boolean
};

type State = {
  numClicks: number // debug
  descriptionText: string;
}

class PointNodeComponent extends LifecycleHandlerBase<Props, State> {
  public container: Pixi.Container;
  public state: State;

  public sprite: Pixi.Sprite
  public halfwayCenterSprite: Pixi.Sprite;
  public centerSprite: Pixi.Sprite;
  public hitArea: Pixi.IHitArea;

  public tooltippableArea?: TooltippableAreaComponent

  constructor(props: Props) {
    super(props);
    this.state = {
      numClicks: 0,
      descriptionText: '',
    };
    this.updateSelf(props); // initialize the description text properly
    this.container = new Pixi.Container();

    this.container.sortableChildren = true;
    this.sprite = new Pixi.Sprite(props.args.pointNodeTexture);
    this.sprite.anchor.x = 0.5;
    this.sprite.anchor.y = 0.5;
    this.sprite.zIndex = -1;
    this.container.addChild(this.sprite);

    this.centerSprite = new Pixi.Sprite(props.args.pointNodeTexture);
    this.centerSprite.anchor.x = 0.5;
    this.centerSprite.anchor.y = 0.5;
    this.centerSprite.scale = PixiPointFrom(new Vector2(0.5, 0.5));
    this.centerSprite.zIndex = 1;
    this.centerSprite.alpha = 0; // TESTING
    // this.container.addChild(this.centerSprite);

    this.halfwayCenterSprite = new Pixi.Sprite(props.args.pointNodeTexture);
    this.halfwayCenterSprite.anchor.x = 0.5;
    this.halfwayCenterSprite.anchor.y = 0.5;
    this.halfwayCenterSprite.scale = PixiPointFrom(new Vector2(0.75, 0.75));
    this.halfwayCenterSprite.zIndex = 0;
    // disable this sprite for now - causes a fairly significant fps hit, until we get around to holding less nodes on the page at once
    this.halfwayCenterSprite.alpha = 0;
    // this.container.addChild(this.halfwayCenterSprite);

    this.container.interactive = true;
    // NOTE(bowei): ive tested, the following 2 settings don't significantly affect FPS
    this.container.buttonMode = true;
    this.hitArea = new Pixi.Rectangle(
      - RenderedChunkConstants.NODE_HITAREA_PX / 2,
      - RenderedChunkConstants.NODE_HITAREA_PX / 2,
      RenderedChunkConstants.NODE_HITAREA_PX,
      RenderedChunkConstants.NODE_HITAREA_PX,
    );
    // note: hitarea breaks child onhover: https://github.com/pixijs/pixi.js/issues/5837
    this.container.hitArea = this.hitArea;

    // const tooltippableAreaPropsFactory = (p: Props, s: State) => {
    //   let nodeDescription: string = "Nothing (empty node)";
    //   if (p.pointNodeGen.resourceType !== ResourceType.Nothing) {
    //     nodeDescription = `${p.pointNodeGen.resourceAmount} ${p.pointNodeGen.resourceModifier} ${p.pointNodeGen.resourceType}`;
    //   }
    //   return {
    //     args: {
    //       markForceUpdate: this.markForceUpdate,
    //     },
    //     text: nodeDescription,
    //     hitArea: this.hitArea, // TODO(bowei): move into state???
    //   }
    // }
    // this.tooltippableArea = new TooltippableAreaComponent(tooltippableAreaPropsFactory(props, this.state));
    // this.container.addChild(this.tooltippableArea.container);
    // this.addChild({
    //   childClass: TooltippableAreaComponent,
    //   instance: this.tooltippableArea,
    //   propsFactory: tooltippableAreaPropsFactory,
    // });
  }

  protected updateSelf(props: Props) {
    let nodeDescription: string = "Nothing (empty node)";
    if (props.pointNodeGen.resourceType !== ResourceType.Nothing) {
      nodeDescription = `${props.pointNodeGen.resourceAmount} ${props.pointNodeGen.resourceModifier} ${props.pointNodeGen.resourceType}`;
    }
    this.state.descriptionText = nodeDescription;
  }

  protected renderSelf(props: Props) {
    this.container.position = PixiPointFrom(props.position);
    let tint: number;
    let centerTint: number;
    if (props.isSelected) {
      tint = 0xBBBBFF;
      centerTint = 0xBBBBFF;
    } else {
      tint = 0xFFFFFF;
      centerTint = 0xFFFFFF;
    }
    if (props.isAllocated) {
      tint = 0x444444;
    } else {
    }
    let baseColor: number = 0;
    if (props.pointNodeGen.resourceType === ResourceType.Nothing) {
      baseColor = 0x99bbff; // blue that mixes in with bg
    } else if (props.pointNodeGen.resourceType === ResourceType.Mana0) {
      if (props.pointNodeGen.resourceModifier === ResourceModifier.Flat) {
        baseColor = 0xeeaaaa; // pink
      } else if (props.pointNodeGen.resourceModifier === ResourceModifier.Increased0) {
        baseColor = 0xcc88ee; // lavender?
      }
    }
    // switch (props.pointNodeGen.resourceType) {
    //   case ResourceType.Nothing:
    //     baseColor = 0x99bbff; // blue that mixes in with bg
    //     break;
    //   case ResourceType.Mana0:
    //     baseColor = 0xeeaaaa; // red
    //     break;
    //   case ResourceType.Mana1:
    //     baseColor = 0xbb7733; // brown?
    //     break;
    //   case ResourceType.Mana2:
    //     baseColor = 0x44aa44; // green
    //     break;
    // }

    this.sprite.tint = multiplyColor(baseColor, tint);
    this.centerSprite.tint = multiplyColor(baseColor, centerTint);

    // NOTE(bowei): careful, we dont want to set the scale of our tooltip to be bigger
    if (props.selfPointNodeRef.pointNodeCoord.equals(Vector2.Zero)) {
      this.container.scale = PixiPointFrom(new Vector2(1.25, 1.25));
    }
  }

  protected shouldUpdate(staleProps: Props, staleState: State, props: Props, state: State): boolean {
    for (let key of (Object.keys(staleProps) as (keyof Props)[])) {
      if (key === 'delta' || key === 'args' || key === 'updaters') { continue; }
      if (staleProps[key] !== props[key]) {
        return true;
      }
      if (key === 'position') {
        if (!staleProps[key].equals(props[key])) {
          console.log(`chunk shouldUpdate differed in ${key}, returning true`);
          return true;
        } else {
          continue;
        }
      }
      if (key === 'selfPointNodeRef') {
        if (staleProps[key]?.hash() !== props[key]?.hash()) {
          console.log(`chunk shouldUpdate differed in ${key}, returning true`);
          return true;
        } else {
          continue;
        }
      }
    }
    return false;
  }

  protected didMount() {
    const { updaters } = this._staleProps; // we assume this will never change

//     this.container.addListener('pointerover', (event: Pixi.InteractionEvent) => {
//       this.state.pointerover = event;
//     })
//     this.container.addListener('pointerout', () => {
//       this.state.pointerover = undefined;
//     })
// 

    this.container.addListener("pointerdown", (event: Pixi.InteractionEvent) => {
      this._staleProps.args.markForceUpdate(this);
      this.state.numClicks++;
      selectOrReselectNode(updaters, this._staleProps.selfPointNodeRef);
      // event.stopPropagation();
    });

    this.container.addListener('pointerover', (event: Pixi.InteractionEvent) => {
      // this._staleProps.args.markForceUpdate(this);

      // source: https://www.iwm-tuebingen.de/iwmbrowser/lib/pixi/tooltip.js
      const localPosition = event.data.getLocalPosition(this.container);
      const position = new Vector2(this.container.worldTransform.tx, this.container.worldTransform.ty);
      // const position = new Vector2(this.container.worldTransform.tx, this.container.worldTransform.ty);

      this._staleProps.tooltipUpdaters.enqueueUpdate((prev) => {
        const next = { ...prev, visible: true, text: this.state.descriptionText, position: position.add(localPosition) };
        // console.log({ next });
        return next;
      })
    });

    this.container.addListener('pointerout', (event: Pixi.InteractionEvent) => {
      // this._staleProps.args.markForceUpdate(this);

      this._staleProps.tooltipUpdaters.enqueueUpdate((prev) => {
        const next = { ...prev, visible: false, text: '' };
        return next;
      })
    });

    this.container.addListener('pointermove', (event: Pixi.InteractionEvent) => {
      // this._staleProps.args.markForceUpdate(this);

      // source: https://www.iwm-tuebingen.de/iwmbrowser/lib/pixi/tooltip.js
      const localPosition = event.data.getLocalPosition(this.container);
      const position = new Vector2(this.container.worldTransform.tx, this.container.worldTransform.ty);

      this._staleProps.tooltipUpdaters.position.enqueueUpdate(position.add(localPosition));
    })
  }

  public toString(): string {
    return "PointNodeCompoent " + this._staleProps.selfPointNodeRef.toString();
  }
}

const wrapped = engageLifecycle(PointNodeComponent);
// eslint-disable-next-line
type wrapped = PointNodeComponent;
export { wrapped as PointNodeComponent };
export type { Props as PointNodeComponentProps };