import { View, Image, Text } from '@tarojs/components';
import { useEffect, useState } from 'react';
import './index.less';

/**
 * 通用 Toast 组件（单例模式）
 *
 * 全局仅存在一个 ToastManager 实例统一管理提示状态与计时器，
 * 无论调用多少次、页面中挂载多少个 <Toast /> 容器，同一时刻只会展示一条提示。
 *
 * 使用方式类似 Taro.showToast：
 *   import { showToast, hideToast } from '@/robotaxi/components/toast';
 *   showToast({ title: '协议获取失败，请重试', icon: 'none' });
 *
 * ⚠️ 需要在页面（或公共布局根组件）中挂载一次 <Toast /> 容器：
 *   import Toast from '@/robotaxi/components/toast';
 *   <Toast />
 */

// 5 种图标样式：成功、失败、告警、加载中、无图标
export type ToastIcon = 'success' | 'fail' | 'warning' | 'loading' | 'none';

export interface ToastOptions {
  /** 提示文本，支持一行或两行 */
  title: string;
  /** 图标类型，默认 none */
  icon?: ToastIcon;
  /**
   * 自动关闭时长（ms）。默认 1500；
   * loading 默认不自动关闭（0），需手动调用 hideToast()
   */
  duration?: number;
  /** 是否显示透明蒙层，阻止穿透点击，默认 false */
  mask?: boolean;
}

/** 内部状态：null 表示当前无提示 */
type ToastState = Required<Omit<ToastOptions, 'duration'>> | null;

type Listener = (state: ToastState) => void;

// OSS 图标资源
const ICON_MAP: Record<Exclude<ToastIcon, 'none'>, string> = {
  success: 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/toast-icon-check-0727@2x.png.png',
  fail: 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/toast-icon-close-0727@2x.png.png',
  warning: 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/toast-icon-error-0727@2x.png',
  loading: 'https://s.xiaopeng.com/xp-fe/robot-taxi/imgs/v2/toast-icon-loading-0727@2x.png'
};

const DEFAULT_DURATION = 1500;

/**
 * Toast 单例管理器：全局唯一，统一维护提示状态与自动关闭计时器。
 * 所有挂载的 <Toast /> 容器订阅同一状态，保证同一时刻只展示一条提示。
 */
class ToastManager {
  private static instance: ToastManager | null = null;

  private listeners = new Set<Listener>();
  private timer: ReturnType<typeof setTimeout> | null = null;
  private state: ToastState = null;

  static getInstance(): ToastManager {
    if (!ToastManager.instance) {
      ToastManager.instance = new ToastManager();
    }
    return ToastManager.instance;
  }

  subscribe(listener: Listener): () => void {
    this.listeners.add(listener);
    // 新容器挂载时同步当前状态
    listener(this.state);
    return () => {
      this.listeners.delete(listener);
    };
  }

  private clearTimer() {
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
  }

  private emit() {
    this.listeners.forEach((l) => l(this.state));
  }

  show(options: ToastOptions) {
    this.clearTimer();
    const icon = options.icon || 'none';
    this.state = {
      title: options.title,
      icon,
      mask: options.mask ?? false
    };
    this.emit();

    // loading 默认不自动关闭，其余默认 1500ms
    const duration =
      typeof options.duration === 'number'
        ? options.duration
        : icon === 'loading'
        ? 0
        : DEFAULT_DURATION;

    if (duration > 0) {
      this.timer = setTimeout(() => this.hide(), duration);
    }
  }

  hide() {
    this.clearTimer();
    this.state = null;
    this.emit();
  }
}

const manager = ToastManager.getInstance();

/** 显示 Toast */
export function showToast(options: ToastOptions) {
  manager.show(options);
}

/** 隐藏 Toast */
export function hideToast() {
  manager.hide();
}

export default function Toast() {
  const [state, setState] = useState<ToastState>(null);

  useEffect(() => {
    const unsubscribe = manager.subscribe(setState);
    return unsubscribe;
  }, []);

  if (!state) {
    return null;
  }

  const { title, icon, mask } = state;
  const hasIcon = icon !== 'none' && !!ICON_MAP[icon];

  return (
    <View className='universal-toast'>
      {mask && <View className='universal-toast__mask' catchMove />}
      <View className={`universal-toast__box ${hasIcon ? 'has-icon' : 'text-only'}`}>
        {hasIcon && (
          <Image
            className={`universal-toast__icon ${icon === 'loading' ? 'is-loading' : ''}`}
            src={ICON_MAP[icon]}
          />
        )}
        <Text className='universal-toast__title'>{title}</Text>
      </View>
    </View>
  );
}
