///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
// All rights reserved.
//
// This software and its documentation and related materials are owned by
// the Alliance. The software may only be incorporated into application
// programs owned by members of the Alliance, subject to a signed
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable
// trade secrets of the Alliance and its suppliers. The software is also
// protected by copyright law and international treaty provisions. Application
// programs incorporating this software must include the following statement
// with their copyright notices:
//
//   This application incorporates Open Design Alliance software pursuant to a
//   license agreement with Open Design Alliance.
//   Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
//   All rights reserved.
//
// By use of this software, its documentation or related materials, you
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////

// ===================== AI-CODE-FILE ======================
// Source: Claude Sonnet 4.5
// Date: 2025-10-07
// Reviewer: vitaly.ivanov@opendesign.com
// Issue: CLOUD-5851
// Notes: Originally AI-generated, modified manually
// =========================================================

interface JoyStickStatus {
  x: number;
  y: number;
  global: any;
}

export class OdJoyStickDragger {
  private onMouseDown: (event?: any) => void;
  private onMouseMove: (event: any) => void;
  private onMouseUp: (event?: any) => void;
  private drawExternal: () => void;
  private drawInternal: () => void;
  private canvas: HTMLCanvasElement;
  private onResize: () => void;
  private hasEventListeners: boolean = false;
  private container: HTMLElement;

  constructor(
    global: any,
    container: HTMLElement,
    callback: (status: JoyStickStatus) => void,
    canvasElement?: HTMLCanvasElement
  ) {
    const internalLineWidth = 2;
    const internalStrokeColor = "#003300";
    const externalLineWidth = 2;
    const externalStrokeColor = "#35436E";

    this.container = container;
    this.container.style.touchAction = "none";

    this.canvas = document.createElement("canvas");
    this.canvas.id = "odJoyStickCanvas";
    this.canvas.width = 200;
    this.canvas.height = 200;
    this.container.appendChild(this.canvas);
    const context = this.canvas.getContext("2d")!;

    let pressed = 0;
    const circumference = 2 * Math.PI;
    const internalRadius = (this.canvas.width - (this.canvas.width / 2 + 10)) / 2;
    const maxMoveStick = internalRadius + 5;
    const externalRadius = internalRadius + 30;
    const centerX = this.canvas.width / 2;
    const centerY = this.canvas.height / 2;
    let movedX = centerX;
    let movedY = centerY;

    this.onMouseDown = () => {
      event.preventDefault();
      pressed = 1;
    };

    this.onMouseMove = (event) => {
      event.preventDefault();
      if (pressed === 1) {
        movedX = event.pageX;
        movedY = event.pageY;
        if (this.canvas.offsetParent && (this.canvas.offsetParent as HTMLElement).tagName.toUpperCase() === "BODY") {
          movedX -= this.canvas.offsetLeft;
          movedY -= this.canvas.offsetTop;
        } else if (this.canvas.offsetParent) {
          movedX -= (this.canvas.offsetParent as HTMLElement).offsetLeft;
          movedY -= (this.canvas.offsetParent as HTMLElement).offsetTop;
        }
        context.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.drawExternal();
        this.drawInternal();
        callback({
          x: 100 * ((movedX - centerX) / maxMoveStick),
          y: 100 * ((movedY - centerY) / maxMoveStick) * -1,
          global,
        });
      }
    };

    this.onMouseUp = () => {
      event.preventDefault();
      pressed = 0;
      movedX = centerX;
      movedY = centerY;
      context.clearRect(0, 0, this.canvas.width, this.canvas.height);
      this.drawExternal();
      this.drawInternal();
      callback({
        x: 100 * ((movedX - centerX) / maxMoveStick),
        y: 100 * ((movedY - centerY) / maxMoveStick) * -1,
        global,
      });
    };

    this.drawExternal = () => {
      context.beginPath();
      context.arc(centerX, centerY, externalRadius, 0, circumference, false);
      context.lineWidth = externalLineWidth;
      context.strokeStyle = externalStrokeColor;
      context.globalAlpha = 0.5;
      context.stroke();
    };

    this.drawInternal = () => {
      context.beginPath();
      if (movedX < internalRadius) {
        movedX = maxMoveStick;
      }
      if (movedX + internalRadius > this.canvas.width) {
        movedX = this.canvas.width - maxMoveStick;
      }
      if (movedY < internalRadius) {
        movedY = maxMoveStick;
      }
      if (movedY + internalRadius > this.canvas.height) {
        movedY = this.canvas.height - maxMoveStick;
      }
      context.arc(movedX, movedY, internalRadius, 0, circumference, false);
      context.fillStyle = externalStrokeColor;
      context.lineWidth = internalLineWidth;
      context.strokeStyle = internalStrokeColor;
      context.globalAlpha = 0.5;
      context.fill();
      context.stroke();
    };

    const addEventListeners = () => {
      if (!this.hasEventListeners) {
        this.canvas.addEventListener("pointerdown", this.onMouseDown, false);
        document.addEventListener("pointermove", this.onMouseMove, false);
        document.addEventListener("pointerup", this.onMouseUp, false);
        this.hasEventListeners = true;
      }
    };

    const removeEventListeners = () => {
      if (this.hasEventListeners) {
        this.canvas.removeEventListener("pointerdown", this.onMouseDown, false);
        document.removeEventListener("pointermove", this.onMouseMove, false);
        document.removeEventListener("pointerup", this.onMouseUp, false);
        this.hasEventListeners = false;
      }
    };

    const updateContainerPosition = () => {
      if (canvasElement) {
        const rect = canvasElement.getBoundingClientRect();
        this.container.style.top = `${rect.height - 200}px`;
        this.container.style.left = `${rect.left}px`;
        this.container.style.width = `200px`;
        this.container.style.height = `200px`;
      }
    };

    const updateVisibility = () => {
      const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
      const isNarrowScreen = window.innerWidth < 1024;
      const shouldShow = isMobile || isNarrowScreen;

      if (shouldShow) {
        this.container.style.display = "block";
        addEventListeners();
      } else {
        this.container.style.display = "none";
        removeEventListeners();
      }
    };

    this.onResize = () => {
      updateVisibility();
      setTimeout(updateContainerPosition, 500);
    };

    updateVisibility();
    updateContainerPosition();
    window.addEventListener("resize", this.onResize, false);

    this.drawExternal();
    this.drawInternal();
  }

  cleanup(): void {
    window.removeEventListener("resize", this.onResize, false);

    if (this.hasEventListeners) {
      this.canvas.removeEventListener("pointerdown", this.onMouseDown, false);
      document.removeEventListener("pointermove", this.onMouseMove, false);
      document.removeEventListener("pointerup", this.onMouseUp, false);
      this.hasEventListeners = false;
    }

    this.canvas.remove();
  }
}
