/**
 * Pure Website Tracking SDK for Tianji
 * Simple event tracking without DOM manipulation or auto-tracking
 */

import { IdentifyPayload } from '../types';
import { BatchManager, BatchItem } from '../utils/batch-manager';

/**
 * Website event payload interface
 */
export interface WebsiteEventPayload {
  /**
   * Website identifier (required)
   */
  website: string;
  /**
   * Current hostname
   */
  hostname?: string;
  /**
   * Screen resolution
   */
  screen?: string;
  /**
   * Browser language
   */
  language?: string;
  /**
   * Page title
   */
  title?: string;
  /**
   * Current URL
   */
  url?: string;
  /**
   * Referrer URL
   */
  referrer?: string;
  /**
   * Event name (for custom events)
   */
  name?: string;
  /**
   * Event data
   */
  data?: Record<string, any>;
}

/**
 * Website identify payload interface
 */
export interface WebsiteIdentifyPayload extends WebsiteEventPayload {
  /**
   * User identification data (required for identify)
   */
  data: Record<string, any>;
}

/**
 * Batch request item interface
 */
export interface BatchRequestItem {
  type: 'event' | 'identify';
  payload: WebsiteEventPayload | WebsiteIdentifyPayload;
}

/**
 * Options for website tracking
 */
export interface WebsiteTrackingOptions {
  /**
   * Your Tianji server URL
   * @example https://tianji.example.com
   */
  serverUrl: string;
  /**
   * Website identifier
   */
  websiteId: string;
  /**
   * Batch delay in milliseconds (optional, defaults to 200ms)
   */
  batchDelay?: number;
  /**
   * Disable batch mode and send requests immediately (optional, defaults to false)
   */
  disableBatch?: boolean;
}

let options: WebsiteTrackingOptions | undefined;
let batchManager: BatchManager<
  WebsiteEventPayload | WebsiteIdentifyPayload
> | null = null;

/**
 * Initialize website tracking
 */
export function initWebsiteTracking(_options: WebsiteTrackingOptions) {
  options = _options;

  // Initialize batch manager
  batchManager = new BatchManager({
    batchDelay: _options.batchDelay,
    disableBatch: _options.disableBatch,
    onBatchSend: async (items) => {
      await sendBatchRequest(_options.serverUrl, items);
    },
    onSingleSend: async (item) => {
      await sendSingleRequest(
        _options.serverUrl,
        item.type as 'event' | 'identify',
        item.payload
      );
    },
  });
}

/**
 * Get basic browser information if available
 */
function getBrowserInfo(): Partial<WebsiteEventPayload> {
  if (typeof window === 'undefined') {
    return {};
  }

  const {
    screen: { width, height },
    navigator: { language },
    location: { hostname, pathname, search },
    document: { title, referrer },
  } = window;

  return {
    hostname,
    screen: `${width}x${height}`,
    language,
    title,
    url: `${pathname}${search}`,
    referrer: referrer || undefined,
  };
}

/**
 * Send website page view event to Tianji server
 */
export async function trackPageView(
  url?: string,
  title?: string
): Promise<void> {
  if (!options) {
    console.warn('Website tracking is not initialized');
    return;
  }

  const browserInfo = getBrowserInfo();
  const payload: WebsiteEventPayload = {
    website: options.websiteId,
    ...browserInfo,
    ...(url && { url }),
    ...(title && { title }),
  };

  sendWebsiteRequest(options.serverUrl, 'event', payload);
}

/**
 * Send custom website event to Tianji server
 *
 * @param eventName - Name of the event
 * @param eventData - Event data
 */
export async function reportWebsiteEvent(
  eventName: string,
  eventData: Record<string, any> = {}
): Promise<void> {
  if (!options) {
    console.warn('Website tracking is not initialized');
    return;
  }

  const browserInfo = getBrowserInfo();
  const payload: WebsiteEventPayload = {
    website: options.websiteId,
    ...browserInfo,
    name: eventName,
    data: eventData,
  };

  sendWebsiteRequest(options.serverUrl, 'event', payload);
}

/**
 * Identify user for website tracking
 *
 * @param userData - User identification data
 */
export async function identifyWebsiteUser(
  userInfo: IdentifyPayload
): Promise<void> {
  if (!options) {
    console.warn('Website tracking is not initialized');
    return;
  }

  if (!userInfo || Object.keys(userInfo).length === 0) {
    console.warn('User data is required for identification');
    return;
  }

  const browserInfo = getBrowserInfo();
  const payload: WebsiteIdentifyPayload = {
    website: options.websiteId,
    ...browserInfo,
    data: userInfo,
  };

  sendWebsiteRequest(options.serverUrl, 'identify', payload);
}

/**
 * Send website request with automatic batching
 * Events are automatically queued and sent together at fixed intervals (throttling)
 * If queue reaches 100 events, it will be sent immediately
 *
 * @param serverUrl - Tianji server URL
 * @param type - Request type ('event' or 'identify')
 * @param payload - Request payload
 */
function sendWebsiteRequest(
  serverUrl: string,
  type: 'event' | 'identify',
  payload: WebsiteEventPayload | WebsiteIdentifyPayload
): void {
  if (!batchManager) {
    console.warn('Website tracking is not initialized');
    return;
  }

  batchManager.add(type, payload);
}

/**
 * Send single request to Tianji website API (fallback when batch is disabled)
 *
 * @param serverUrl - Tianji server URL
 * @param type - Request type ('event' or 'identify')
 * @param payload - Request payload
 */
async function sendSingleRequest(
  serverUrl: string,
  type: 'event' | 'identify',
  payload: WebsiteEventPayload | WebsiteIdentifyPayload
): Promise<void> {
  try {
    const response = await fetch(`${serverUrl}/api/website/send`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        type,
        payload,
      }),
    });

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`Failed to send website ${type}: ${errorText}`);
    }
  } catch (error) {
    console.error(`Error sending website ${type}:`, error);
    return; // As event tracking SDK, should not throw error which maybe cause crash
  }
}

/**
 * Send batch request to Tianji website API
 */
async function sendBatchRequest(
  serverUrl: string,
  items: BatchItem[]
): Promise<void> {
  try {
    const response = await fetch(`${serverUrl}/api/website/batch`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        events: items,
      }),
    });

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`Failed to send batch request: ${errorText}`);
    }
  } catch (error) {
    console.error('Error sending batch request:', error);
    return; // As event tracking SDK, should not throw error which maybe cause crash
  }
}

/**
 * Flush batch queue manually (send all pending requests immediately)
 * Useful for ensuring events are sent before page unload
 */
export async function flushBatchQueue(): Promise<void> {
  if (batchManager) {
    await batchManager.flush();
  }
}
