import { TrackerConfig, TrackEvent, EventType, EventKey, validateEventKeyType, getDefaultEventType } from "./types";
import { getSessionId, getDeviceId, formatDateTime } from "../utils";

/**
 * 核心追踪器类
 */
class Tracker {
  private config: TrackerConfig;
  private sessionId: string;
  public version: string = "1.0.0";
  private eventQueue: TrackEvent[] = [];
  private readonly BATCH_SIZE = 5;

  /**
   * 构造函数
   */
  constructor(config?: Partial<TrackerConfig>) {
    // 默认配置
    const defaultConfig: TrackerConfig = {
      project_id: "",
      server_url: "https://api.zdcloud.click",
      event_path: "/api/sdk/collect/track",
      batch_event_path: "/api/sdk/collect/batch",
      enable_auto_track: true,
      debug: true,
    };

    this.config = { ...defaultConfig, ...config };
    this.sessionId = getSessionId();

    // 监听页面卸载事件，发送剩余事件
    this.setupUnloadHandler();
  }

  /**
   * 设置页面卸载处理器
   */
  private setupUnloadHandler(): void {
    if (typeof window !== "undefined") {
      const handleUnload = () => {
        if (this.eventQueue.length > 0) {
          this.batchSend(true);
        }
      };

      // 监听页面卸载事件
      window.addEventListener('beforeunload', handleUnload);
      window.addEventListener('pagehide', handleUnload);

      // 对于现代浏览器，使用visibilitychange事件
      document.addEventListener('visibilitychange', () => {
        if (document.visibilityState === 'hidden' && this.eventQueue.length > 0) {
          this.batchSend(true);
        }
      });
    }
  }

  /**
   * 验证事件数据
   * @param event 事件数据
   */
  private validateEvent(event: TrackEvent): void {
    // 验证必填字段
    if (!event.project_id?.trim()) {
      throw new Error('项目ID不能为空');
    }

    if (!event.session_id?.trim()) {
      throw new Error('会话ID不能为空');
    }

    if (!event.event_time) {
      throw new Error('事件时间不能为空');
    }

    // 验证事件键
    if (!Object.values(EventKey).includes(event.event_key)) {
      throw new Error(`无效的事件键: ${event.event_key} \r\n支持的键: ${Object.values(EventKey).join(', ')}`);
    }

    // 验证事件类型
    if (!Object.values(EventType).includes(event.event_type)) {
      throw new Error(`无效的事件类型: ${event.event_type} \r\n支持的事件类型: ${Object.values(EventType).join(', ')}`);
    }

    // 验证事件键和事件类型的组合
    if (!validateEventKeyType(event.event_key, event.event_type)) {
      const expectedType = getDefaultEventType(event.event_key);
      throw new Error(`事件键 "${event.event_key}" 与事件类型 "${event.event_type}" 的组合无效。该事件键应使用事件类型: ${expectedType}`);
    }
  }

  /**
   * 添加事件到队列
   * @param event 事件数据
   */
  private addToQueue(event: TrackEvent): void {
    try {
      // 客户端验证
      this.validateEvent(event);

      if (this.config.debug) {
        console.log(`[KTrace] 添加事件到队列:`, event);
      }

      this.eventQueue.push(event);

      // 检查是否需要发送
      if (this.eventQueue.length >= this.BATCH_SIZE) {
        this.batchSend();
      }
    } catch (error) {
      console.error(`[KTrace] 事件验证失败:`, (error as Error).message);
    }
  }

  /**
   * 批量发送事件
   * @param isUnload 是否是页面卸载时的发送
   */
  private batchSend(isUnload: boolean = false): void {
    if (this.eventQueue.length === 0) {
      return;
    }

    // sendBeacon检查
    if (typeof navigator === 'undefined' || !navigator.sendBeacon) {
      console.error('[KTrace] sendBeacon不支持，无法发送事件');
      return;
    }

    const server_url = this.config.server_url!;
    const batch_event_path = this.config.batch_event_path!;
    const url = server_url + batch_event_path;

    // 构建批量数据
    const batchData = {
      events: [...this.eventQueue],
      batch_info: {
        batch_size: this.eventQueue.length,
        timestamp: formatDateTime(new Date()),
        is_unload: isUnload
      }
    };

    try {
      // 使用sendBeacon发送数据
      const blob = new Blob([JSON.stringify(batchData)], {
        type: 'application/json'
      });

      const success = navigator.sendBeacon(url, blob);

      if (success) {
        if (this.config.debug) {
          console.log(`[KTrace] 批量发送成功，事件数量: ${this.eventQueue.length}`, batchData);
        }
        // 清空队列
        this.eventQueue = [];
      } else {
        console.error('[KTrace] sendBeacon发送失败');
      }
    } catch (error) {
      console.error('[KTrace] 批量发送事件时发生错误:', error);
    }
  }

  /**
   * 手动触发批量发送
   * 用于在需要时立即发送当前队列中的所有事件
   */
  public flushEvents(): void {
    if (this.eventQueue.length > 0) {
      this.batchSend();
    }
  }

  /**
   * 创建基础事件对象 
   */
  public createBaseEvent(
    eventKey: EventKey,
    eventType?: EventType,
    error?: Error,
    properties?: Record<string, any>
  ): TrackEvent {
    // 如果没有指定事件类型，使用默认类型
    const finalEventType = eventType || getDefaultEventType(eventKey);

    const eventInfo = properties || {};
    const page_url = typeof window !== "undefined" && window.location ? window.location.href : ""
    const referrer = typeof document !== "undefined" ? document.referrer : ""

    const metadata: any = {
      ...eventInfo,
      page_url,
      referrer,
    }

    if (finalEventType === EventType.ERROR) {
      metadata.error_message = error?.message;
      metadata.error_stack = error?.stack;
      metadata.error_name = error?.name;
    }

    return {
      project_id: this.config.project_id,
      event_key: eventKey,
      event_type: finalEventType,
      event_time: new Date(),
      session_id: this.sessionId,
      device_id: getDeviceId(),
      device_ua: typeof navigator !== "undefined" ? navigator.userAgent : "",
      ip_address: '',
      metadata: metadata,
    };
  }

  /**
   * 追踪自定义事件
   * @param eventName 事件名称（必须是EventKey枚举值）
   * @param properties 事件属性
   */
  public trackEvent(eventName: EventKey, properties?: Record<string, any>): void {
    const event = this.createBaseEvent(eventName, undefined, undefined, properties);
    this.addToQueue(event);
  }

  /**
   * 追踪错误事件
   * @param error 错误对象
   * @param eventKey 错误事件键（可选，默认使用JAVASCRIPT_ERROR）
   * @param properties 附加属性
   */
  public trackError(error: Error, eventKey: EventKey = EventKey.JAVASCRIPT_ERROR, properties?: Record<string, any>): void {
    const event = this.createBaseEvent(eventKey, EventType.ERROR, error, properties);
    this.addToQueue(event);
  }

  /**
   * 获取当前队列长度
   */
  public getQueueLength(): number {
    return this.eventQueue.length;
  }

  public getConfig(): TrackerConfig {
    return this.config;
  }
}

export default Tracker;