import { Logger } from '../utils/Logger';
import { FingerprintManager } from './FingerprintManager';

interface ShipInfo {
  orderId: string;
  platform: string;
  shopId: string;
  trackingNumber: string;
  carrier: string;
  items: Array<{
    productId: string;
    skuId: string;
    quantity: number;
  }>;
  shippingAddress: {
    name: string;
    phone: string;
    address: string;
    city: string;
    state: string;
    zipCode: string;
    country: string;
  };
}

interface ShipResult {
  success: boolean;
  orderId: string;
  trackingNumber?: string;
  carrier?: string;
  status: 'shipped' | 'failed' | 'pending';
  message: string;
  timestamp: string;
  traceId: string;
}

interface ShipTask {
  taskId: string;
  orderId: string;
  shopId: string;
  platform: string;
  status: 'pending' | 'processing' | 'completed' | 'failed';
  retryCount: number;
  maxRetries: number;
  createdAt: string;
  updatedAt: string;
  traceId: string;
}

export class AutoShipService {
  private logger = new Logger('AutoShipService');
  private fingerprintManager: FingerprintManager;
  private tasks: Map<string, ShipTask> = new Map();
  private readonly MAX_RETRIES = 3;
  private readonly RETRY_DELAY_MS = 5000;

  constructor(fingerprintManager: FingerprintManager) {
    this.fingerprintManager = fingerprintManager;
  }

  async createShipTask(shipInfo: ShipInfo, traceId?: string): Promise<ShipTask> {
    const tid = traceId || this.generateTraceId();
    const taskId = `SHIP-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

    this.logger.info('Creating ship task', {
      taskId,
      orderId: shipInfo.orderId,
      platform: shipInfo.platform,
      traceId: tid,
    });

    const task: ShipTask = {
      taskId,
      orderId: shipInfo.orderId,
      shopId: shipInfo.shopId,
      platform: shipInfo.platform,
      status: 'pending',
      retryCount: 0,
      maxRetries: this.MAX_RETRIES,
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
      traceId: tid,
    };

    this.tasks.set(taskId, task);

    await this.reportTaskCreated(task);

    return task;
  }

  async processShipTask(taskId: string, shipInfo: ShipInfo): Promise<ShipResult> {
    const task = this.tasks.get(taskId);
    if (!task) {
      throw new Error(`Task not found: ${taskId}`);
    }

    task.status = 'processing';
    task.updatedAt = new Date().toISOString();

    this.logger.info('Processing ship task', {
      taskId,
      orderId: task.orderId,
      platform: task.platform,
      traceId: task.traceId,
    });

    try {
      const context = await this.fingerprintManager.createIsolatedContext(
        task.shopId,
        undefined,
        task.traceId
      );

      if (!context.success || !context.context) {
        throw new Error(`Failed to create isolated context: ${context.error}`);
      }

      const result = await this.executeShipOperation(task, shipInfo, context.context);

      if (result.success) {
        task.status = 'completed';
        this.logger.info('Ship task completed', {
          taskId,
          orderId: task.orderId,
          trackingNumber: result.trackingNumber,
          traceId: task.traceId,
        });
      } else if (task.retryCount < task.maxRetries) {
        task.retryCount++;
        task.status = 'pending';
        this.logger.warn('Ship task failed, will retry', {
          taskId,
          orderId: task.orderId,
          retryCount: task.retryCount,
          error: result.message,
          traceId: task.traceId,
        });

        setTimeout(() => {
          this.processShipTask(taskId, shipInfo);
        }, this.RETRY_DELAY_MS * task.retryCount);
      } else {
        task.status = 'failed';
        this.logger.error('Ship task failed after max retries', {
          taskId,
          orderId: task.orderId,
          error: result.message,
          traceId: task.traceId,
        });
      }

      task.updatedAt = new Date().toISOString();
      await this.reportTaskStatus(task, result);

      return result;
    } catch (error: any) {
      task.status = 'failed';
      task.updatedAt = new Date().toISOString();

      this.logger.error('Ship task processing error', {
        taskId,
        orderId: task.orderId,
        error: error.message,
        traceId: task.traceId,
      });

      const errorResult: ShipResult = {
        success: false,
        orderId: task.orderId,
        status: 'failed',
        message: error.message,
        timestamp: new Date().toISOString(),
        traceId: task.traceId,
      };

      await this.reportTaskStatus(task, errorResult);
      return errorResult;
    }
  }

  private async executeShipOperation(
    task: ShipTask,
    shipInfo: ShipInfo,
    context: any
  ): Promise<ShipResult> {
    this.logger.info('Executing ship operation', {
      taskId: task.taskId,
      orderId: task.orderId,
      platform: task.platform,
      traceId: task.traceId,
    });

    try {
      switch (task.platform.toLowerCase()) {
        case 'tiktok':
          return await this.shipTikTokOrder(task, shipInfo, context);
        case 'temu':
          return await this.shipTemuOrder(task, shipInfo, context);
        case '1688':
          return await this.ship1688Order(task, shipInfo, context);
        default:
          throw new Error(`Unsupported platform: ${task.platform}`);
      }
    } catch (error: any) {
      return {
        success: false,
        orderId: task.orderId,
        status: 'failed',
        message: `Ship operation failed: ${error.message}`,
        timestamp: new Date().toISOString(),
        traceId: task.traceId,
      };
    }
  }

  private async shipTikTokOrder(
    task: ShipTask,
    shipInfo: ShipInfo,
    context: any
  ): Promise<ShipResult> {
    this.logger.info('Shipping TikTok order', {
      taskId: task.taskId,
      orderId: task.orderId,
      traceId: task.traceId,
    });

    await this.simulateDelay(2000, 4000);

    const success = Math.random() > 0.1;

    if (success) {
      return {
        success: true,
        orderId: task.orderId,
        trackingNumber: shipInfo.trackingNumber,
        carrier: shipInfo.carrier,
        status: 'shipped',
        message: 'Order shipped successfully on TikTok',
        timestamp: new Date().toISOString(),
        traceId: task.traceId,
      };
    } else {
      return {
        success: false,
        orderId: task.orderId,
        status: 'failed',
        message: 'Failed to ship order on TikTok: Platform validation error',
        timestamp: new Date().toISOString(),
        traceId: task.traceId,
      };
    }
  }

  private async shipTemuOrder(
    task: ShipTask,
    shipInfo: ShipInfo,
    context: any
  ): Promise<ShipResult> {
    this.logger.info('Shipping Temu order', {
      taskId: task.taskId,
      orderId: task.orderId,
      traceId: task.traceId,
    });

    await this.simulateDelay(1500, 3000);

    const success = Math.random() > 0.15;

    if (success) {
      return {
        success: true,
        orderId: task.orderId,
        trackingNumber: shipInfo.trackingNumber,
        carrier: shipInfo.carrier,
        status: 'shipped',
        message: 'Order shipped successfully on Temu',
        timestamp: new Date().toISOString(),
        traceId: task.traceId,
      };
    } else {
      return {
        success: false,
        orderId: task.orderId,
        status: 'failed',
        message: 'Failed to ship order on Temu: Order status not eligible for shipping',
        timestamp: new Date().toISOString(),
        traceId: task.traceId,
      };
    }
  }

  private async ship1688Order(
    task: ShipTask,
    shipInfo: ShipInfo,
    context: any
  ): Promise<ShipResult> {
    this.logger.info('Shipping 1688 order', {
      taskId: task.taskId,
      orderId: task.orderId,
      traceId: task.traceId,
    });

    await this.simulateDelay(2500, 5000);

    const success = Math.random() > 0.2;

    if (success) {
      return {
        success: true,
        orderId: task.orderId,
        trackingNumber: shipInfo.trackingNumber,
        carrier: shipInfo.carrier,
        status: 'shipped',
        message: 'Order shipped successfully on 1688',
        timestamp: new Date().toISOString(),
        traceId: task.traceId,
      };
    } else {
      return {
        success: false,
        orderId: task.orderId,
        status: 'failed',
        message: 'Failed to ship order on 1688: Authentication required',
        timestamp: new Date().toISOString(),
        traceId: task.traceId,
      };
    }
  }

  async batchProcessShipTasks(tasks: Array<{ taskId: string; shipInfo: ShipInfo }>): Promise<ShipResult[]> {
    this.logger.info('Starting batch ship processing', { count: tasks.length });

    const results: ShipResult[] = [];

    for (const { taskId, shipInfo } of tasks) {
      try {
        const result = await this.processShipTask(taskId, shipInfo);
        results.push(result);
      } catch (error: any) {
        results.push({
          success: false,
          orderId: shipInfo.orderId,
          status: 'failed',
          message: `Batch processing error: ${error.message}`,
          timestamp: new Date().toISOString(),
          traceId: shipInfo.orderId,
        });
      }

      await this.simulateDelay(1000, 2000);
    }

    this.logger.info('Batch ship processing completed', {
      total: tasks.length,
      success: results.filter(r => r.success).length,
      failed: results.filter(r => !r.success).length,
    });

    return results;
  }

  getTaskStatus(taskId: string): ShipTask | undefined {
    return this.tasks.get(taskId);
  }

  getTasksByShop(shopId: string): ShipTask[] {
    return Array.from(this.tasks.values()).filter(t => t.shopId === shopId);
  }

  getTasksByStatus(status: ShipTask['status']): ShipTask[] {
    return Array.from(this.tasks.values()).filter(t => t.status === status);
  }

  private async reportTaskCreated(task: ShipTask): Promise<void> {
    this.logger.info('Reporting task created to backend', {
      taskId: task.taskId,
      orderId: task.orderId,
      traceId: task.traceId,
    });
  }

  private async reportTaskStatus(task: ShipTask, result: ShipResult): Promise<void> {
    this.logger.info('Reporting task status to backend', {
      taskId: task.taskId,
      orderId: task.orderId,
      status: task.status,
      traceId: task.traceId,
    });

    try {
      const response = await fetch('http://localhost:3000/api/plugin/ship-status', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          taskId: task.taskId,
          orderId: task.orderId,
          shopId: task.shopId,
          platform: task.platform,
          status: task.status,
          trackingNumber: result.trackingNumber,
          carrier: result.carrier,
          message: result.message,
          timestamp: result.timestamp,
          traceId: task.traceId,
        }),
      });

      if (!response.ok) {
        this.logger.warn('Failed to report task status', {
          taskId: task.taskId,
          statusCode: response.status,
        });
      }
    } catch (error: any) {
      this.logger.warn('Error reporting task status', {
        taskId: task.taskId,
        error: error.message,
      });
    }
  }

  private async simulateDelay(minMs: number, maxMs: number): Promise<void> {
    const delay = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs;
    return new Promise(resolve => setTimeout(resolve, delay));
  }

  private generateTraceId(): string {
    return `trace-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
  }
}
