import {
  _decorator,
  Component,
  Node,
  Prefab,
  instantiate,
  Canvas,
  Vec3,
  find,
  director,
  UITransform,
  resources,
  tween,
  Tween,
} from "cc";
import { TipItem } from "./TipItem";

const { ccclass, property } = _decorator;

@ccclass("Tips")
export class Tips extends Component {
  public static show(content: string, worldPos?: Vec3) {
    Tips.ins.showTip(content, worldPos);
  }

  private static _ins: Tips = null!;

  // TipItem预制体
  @property(Prefab)
  public tipPrefab: Prefab = null!;

  private tipContainer: Node = null!;

  // 对象池
  private tipPool: Node[] = [];
  private activeTips: Node[] = [];

  // 配置参数
  private readonly MAX_POOL_SIZE = 20; // 对象池最大数量
  private readonly MAX_ACTIVE_TIPS = 10; // 同时显示的最大提示数量
  private offsetY = 0; // Y轴偏移，用于错开显示位置

  public static get ins(): Tips {
    return this._ins ??= new Tips();
  }

  protected onLoad(): void {
    Tips._ins = this;
    director.addPersistRootNode(this.node);
    this.createContainer(this.node);
    this.preCreateTipItems();
  }

  /**
   * 创建提示容器
   */
  private createContainer(parent: Node): void {
    // 创建TipContainer
    this.tipContainer = new Node("TipContainer");
    this.tipContainer.addComponent(UITransform);
    this.tipContainer.parent = parent;

    // 设置容器层级较高，确保在最前面显示
    this.tipContainer.setSiblingIndex(999);
  }

  /**
   * 预创建TipItem到对象池
   */
  private preCreateTipItems(): void {
    for (let i = 0; i < 5; i++) {
      const tipNode = this.createTipItem();
      tipNode.active = false;
      this.tipPool.push(tipNode);
    }
  }

  /**
   * 创建TipItem节点
   */
  private createTipItem(): Node {
    if (!this.tipPrefab) {
      console.error("TipItem预制体未加载");
      return null!;
    }

    const tipNode = instantiate(this.tipPrefab);
    tipNode.parent = this.tipContainer;

    // 确保有TipItem组件
    let tipComponent = tipNode.getComponent(TipItem);
    if (!tipComponent) {
      tipComponent = tipNode.addComponent(TipItem);
    }

    return tipNode;
  }

  /**
   * 从对象池获取TipItem
   */
  private getTipItemFromPool(): Node {
    // 先检查是否有可用的池对象
    for (let i = 0; i < this.tipPool.length; i++) {
      const tipNode = this.tipPool[i];
      const tipComponent = tipNode.getComponent(TipItem);
      if (tipComponent && !tipComponent.getIsInUse()) {
        this.tipPool.splice(i, 1);
        return tipNode;
      }
    }

    // 如果池中没有可用对象，且总数未达到上限，创建新的
    const totalCount = this.tipPool.length + this.activeTips.length;
    if (totalCount < this.MAX_POOL_SIZE) {
      return this.createTipItem();
    }

    // 如果达到最大数量，强制回收最老的提示
    if (this.activeTips.length > 0) {
      const oldestTip = this.activeTips[0];
      const tipComponent = oldestTip.getComponent(TipItem);
      if (tipComponent) {
        tipComponent.forceRecycle();
      }
      // 回收后应该有可用的对象了，再次检查池
      for (let i = 0; i < this.tipPool.length; i++) {
        const tipNode = this.tipPool[i];
        const tipComponent = tipNode.getComponent(TipItem);
        if (tipComponent && !tipComponent.getIsInUse()) {
          this.tipPool.splice(i, 1);
          return tipNode;
        }
      }
    }

    // 最后的备选方案，创建新的（但这种情况应该很少发生）
    console.warn("对象池逻辑异常，创建新的TipItem");
    return this.createTipItem();
  }

  /**
   * 回收TipItem到对象池
   */
  public recycleTipItem(tipNode: Node): void {
    // 从激活列表中移除
    const index = this.activeTips.indexOf(tipNode);
    if (index >= 0) {
      this.activeTips.splice(index, 1);
    }

    // 添加到池中（节点已经在TipItem.recycle()中设置为inactive）
    if (this.tipPool.length < this.MAX_POOL_SIZE) {
      this.tipPool.push(tipNode);
    } else {
      // 池已满，销毁节点
      tipNode.destroy();
    }
  }

  /**
   * 调整Y轴偏移
   */
  private adjustOffsetY(): void {
    this.offsetY = Math.max(0, this.offsetY - 80);
  }

  /**
   * 将所有现有的提示向上推移
   */
  private pushExistingTipsUp(): void {
    for (const tipNode of this.activeTips) {
      // 先停止该节点上所有的tween动画，避免动画冲突
      Tween.stopAllByTarget(tipNode);

      const currentPos = tipNode.getPosition();
      const newPos = new Vec3(currentPos.x, currentPos.y + 80, currentPos.z);

      // 使用缓动动画让推移更平滑
      tween(tipNode)
        .to(0.2, { position: newPos }, { easing: "quadOut" })
        .start();
    }
  }

  /**
   * 显示提示
   * @param content 提示内容
   * @param worldPos 世界坐标位置，如果不传则显示在屏幕中心上方
   */
  public showTip(content: string, worldPos?: Vec3): void {
    if (!this.tipContainer) {
      console.error("TipManager未初始化");
      return;
    }

    // 检查是否超过最大显示数量，如果超过则强制回收最老的提示
    if (this.activeTips.length >= this.MAX_ACTIVE_TIPS) {
      const oldestTip = this.activeTips[0];
      const tipComponent = oldestTip.getComponent(TipItem);
      if (tipComponent) {
        tipComponent.forceRecycle();
      }
      // 注意：forceRecycle会调用recycle，recycle会调用recycleTipItem，
      // recycleTipItem会从activeTips中移除，所以这里不需要手动移除
    }

    // 将所有现有的提示向上推移
    //this.pushExistingTipsUp();

    // 获取TipItem
    const tipNode = this.getTipItemFromPool();
    if (!tipNode) {
      console.error("无法获取TipItem");
      return;
    }

    // 计算显示位置 - 新提示始终在基础位置显示
    let displayPos: Vec3;
    if (worldPos) {
      // 转换世界坐标到UI坐标
      displayPos = this.worldToUIPos(worldPos);
    } else {
      // 新提示始终在固定位置显示
      displayPos = new Vec3(0, 200, 0);
    }

    // 添加到激活列表
    this.activeTips.push(tipNode);

    // 初始化并显示
    const tipComponent = tipNode.getComponent(TipItem);
    if (tipComponent) {
      tipComponent.init(content, displayPos);
    }
  }

  /**
   * 将世界坐标转换为UI坐标
   */
  private worldToUIPos(worldPos: Vec3): Vec3 {
    // 这里需要根据实际的坐标系统来转换
    // 简单实现，可以根据需要调整
    return new Vec3(worldPos.x, worldPos.y + 100, 0);
  }

  /**
   * 清除所有提示
   */
  public clearAllTips(): void {
    // 强制回收所有激活的提示
    for (const tipNode of this.activeTips) {
      const tipComponent = tipNode.getComponent(TipItem);
      if (tipComponent) {
        tipComponent.forceRecycle();
      }
    }
  }

  /**
   * 销毁管理器
   */
  public onDestroy(): void {
    if (2 > 1) {
      return;
    }
    this.clearAllTips();

    // 销毁对象池中的所有节点
    for (const tipNode of this.tipPool) {
      tipNode.destroy();
    }

    this.tipPool = [];
    this.activeTips = [];

    // 销毁容器
    if (this.tipContainer) {
      this.tipContainer.destroy();
      this.tipContainer = null!;
    }

    Tips._ins = null!;
  }
}
