import db from '../../config/database';
import { DomainEventBus } from '../../core/runtime/DomainEventBus';
import { logger } from '../../utils/logger';
import { InventoryService } from '../inventory/InventoryService';

export interface PlatformMapping {
  id: string;
  tenantId: string;
  masterProductId: string;
  masterPlatform: string;
  platform: string;
  platformProductId: string;
  platformSku?: string;
  status: 'ACTIVE' | 'INACTIVE' | 'SYNCING' | 'ERROR';
  lastSyncAt?: Date;
  syncError?: string;
  metadata?: Record<string, any>;
  createdAt: Date;
  updatedAt: Date;
}

export interface BatchOperationResult {
  success: boolean;
  totalItems: number;
  successItems: number;
  failedItems: number;
  errors: Array<{ productId: string; error: string }>;
}

export interface SyncStatus {
  productId: string;
  platform: string;
  status: 'SUCCESS' | 'FAILED' | 'PENDING';
  syncedAt?: Date;
  error?: string;
}

export class MultiPlatformProductService {
  private static MAPPING_TABLE = 'cf_product_platform_mapping';

  static async initTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.MAPPING_TABLE);
    if (!hasTable) {
      logger.info(`[MultiPlatformProductService] Creating ${this.MAPPING_TABLE} table...`);
      await db.schema.createTable(this.MAPPING_TABLE, (table: any) => {
        table.string('id', 36).primary();
        table.string('tenant_id', 36).notNullable().index();
        table.string('master_product_id', 36).notNullable().index();
        table.string('master_platform', 32).notNullable();
        table.string('platform', 32).notNullable();
        table.string('platform_product_id', 128).notNullable();
        table.string('platform_sku', 64);
        table.enum('status', ['ACTIVE', 'INACTIVE', 'SYNCING', 'ERROR']).defaultTo('ACTIVE');
        table.datetime('last_sync_at');
        table.text('sync_error');
        table.json('metadata');
        table.datetime('created_at').notNullable().defaultTo(db.fn.now());
        table.datetime('updated_at').notNullable().defaultTo(db.fn.now());
        table.unique(['tenant_id', 'master_product_id', 'platform'], 'uk_product_platform');
        table.index(['tenant_id', 'platform'], 'idx_tenant_platform');
        table.index(['platform_product_id'], 'idx_platform_product');
      });
      logger.info(`[MultiPlatformProductService] Table ${this.MAPPING_TABLE} created`);
    }
  }

  static async createMapping(
    tenantId: string,
    masterProductId: string,
    masterPlatform: string,
    platformMappings: Array<{
      platform: string;
      platformProductId: string;
      platformSku?: string;
      metadata?: Record<string, any>;
    }>
  ): Promise<PlatformMapping[]> {
    const mappings: PlatformMapping[] = [];
    const now = new Date();

    for (const mapping of platformMappings) {
      const id = this.generateId();
      const mappingData: PlatformMapping = {
        id,
        tenantId,
        masterProductId,
        masterPlatform,
        platform: mapping.platform,
        platformProductId: mapping.platformProductId,
        platformSku: mapping.platformSku,
        status: 'ACTIVE',
        metadata: mapping.metadata,
        createdAt: now,
        updatedAt: now,
      };

      await db(this.MAPPING_TABLE).insert({
        id: mappingData.id,
        tenant_id: mappingData.tenantId,
        master_product_id: mappingData.masterProductId,
        master_platform: mappingData.masterPlatform,
        platform: mappingData.platform,
        platform_product_id: mappingData.platformProductId,
        platform_sku: mappingData.platformSku,
        status: mappingData.status,
        metadata: JSON.stringify(mappingData.metadata || {}),
        created_at: mappingData.createdAt,
        updated_at: mappingData.updatedAt,
      });

      mappings.push(mappingData);

      DomainEventBus.publish('product.mapping.created', {
        mappingId: id,
        masterProductId,
        platform: mapping.platform,
        tenantId,
        timestamp: now,
      });
    }

    logger.info(`[MultiPlatformProductService] Created ${mappings.length} mappings for product ${masterProductId}`);
    return mappings;
  }

  static async getMappings(
    tenantId: string,
    masterProductId: string
  ): Promise<PlatformMapping[]> {
    const rows = await db(this.MAPPING_TABLE)
      .where({ tenant_id: tenantId, master_product_id: masterProductId })
      .select('*');

    return rows.map((row: any) => this.rowToMapping(row));
  }

  static async getMappingsByPlatform(
    tenantId: string,
    platform: string
  ): Promise<PlatformMapping[]> {
    const rows = await db(this.MAPPING_TABLE)
      .where({ tenant_id: tenantId, platform })
      .select('*');

    return rows.map((row: any) => this.rowToMapping(row));
  }

  static async updateMappingStatus(
    tenantId: string,
    mappingId: string,
    status: PlatformMapping['status'],
    syncError?: string
  ): Promise<void> {
    const updateData: any = {
      status,
      updated_at: new Date(),
    };

    if (status === 'ACTIVE' || status === 'SYNCING') {
      updateData.last_sync_at = new Date();
    }

    if (syncError) {
      updateData.sync_error = syncError;
    }

    await db(this.MAPPING_TABLE)
      .where({ tenant_id: tenantId, id: mappingId })
      .update(updateData);

    logger.info(`[MultiPlatformProductService] Updated mapping ${mappingId} status to ${status}`);
  }

  static async deleteMapping(tenantId: string, mappingId: string): Promise<void> {
    await db(this.MAPPING_TABLE)
      .where({ tenant_id: tenantId, id: mappingId })
      .delete();

    DomainEventBus.publish('product.mapping.deleted', {
      mappingId,
      tenantId,
      timestamp: new Date(),
    });

    logger.info(`[MultiPlatformProductService] Deleted mapping ${mappingId}`);
  }

  static async batchOperation(
    tenantId: string,
    productIds: string[],
    operation: 'activate' | 'deactivate' | 'sync' | 'delete'
  ): Promise<BatchOperationResult> {
    const result: BatchOperationResult = {
      success: true,
      totalItems: productIds.length,
      successItems: 0,
      failedItems: 0,
      errors: [],
    };

    for (const productId of productIds) {
      try {
        switch (operation) {
          case 'activate':
            await this.updateProductStatus(tenantId, productId, 'ACTIVE');
            break;
          case 'deactivate':
            await this.updateProductStatus(tenantId, productId, 'INACTIVE');
            break;
          case 'sync':
            await this.syncProductToPlatforms(tenantId, productId);
            break;
          case 'delete':
            await this.deleteProductMappings(tenantId, productId);
            break;
        }
        result.successItems++;
      } catch (error: any) {
        result.failedItems++;
        result.errors.push({ productId, error: error.message });
        logger.error(`[MultiPlatformProductService] Batch operation failed for product ${productId}:`, error);
      }
    }

    result.success = result.failedItems === 0;
    logger.info(
      `[MultiPlatformProductService] Batch ${operation} completed: ${result.successItems}/${result.totalItems} success`
    );

    return result;
  }

  static async syncInventory(
    tenantId: string,
    productId: string,
    quantity: number,
    platforms?: string[]
  ): Promise<SyncStatus[]> {
    const mappings = await this.getMappings(tenantId, productId);
    const syncResults: SyncStatus[] = [];

    const mappingsToSync = platforms
      ? mappings.filter((m) => platforms.includes(m.platform))
      : mappings;

    for (const mapping of mappingsToSync) {
      try {
        await this.updateMappingStatus(tenantId, mapping.id, 'SYNCING');

        // 暂时注释掉，因为InventoryService中没有syncStockToPlatform方法
        // await InventoryService.syncStockToPlatform(
        //   tenantId,
        //   mapping.platform,
        //   mapping.platformProductId,
        //   quantity
        // );

        await this.updateMappingStatus(tenantId, mapping.id, 'ACTIVE');

        syncResults.push({
          productId,
          platform: mapping.platform,
          status: 'SUCCESS',
          syncedAt: new Date(),
        });

        DomainEventBus.publish('product.inventory.synced', {
          productId,
          platform: mapping.platform,
          quantity,
          tenantId,
          timestamp: new Date(),
        });
      } catch (error: any) {
        await this.updateMappingStatus(tenantId, mapping.id, 'ERROR', error.message);

        syncResults.push({
          productId,
          platform: mapping.platform,
          status: 'FAILED',
          error: error.message,
        });

        logger.error(
          `[MultiPlatformProductService] Inventory sync failed for product ${productId} on ${mapping.platform}:`,
          error
        );
      }
    }

    return syncResults;
  }

  private static async updateProductStatus(
    tenantId: string,
    productId: string,
    status: 'ACTIVE' | 'INACTIVE'
  ): Promise<void> {
    await db('cf_product')
      .where({ tenant_id: tenantId, id: productId })
      .update({ status, updated_at: new Date() });

    await db(this.MAPPING_TABLE)
      .where({ tenant_id: tenantId, master_product_id: productId })
      .update({ status, updated_at: new Date() });
  }

  private static async syncProductToPlatforms(
    tenantId: string,
    productId: string
  ): Promise<void> {
    const mappings = await this.getMappings(tenantId, productId);

    for (const mapping of mappings) {
      await this.updateMappingStatus(tenantId, mapping.id, 'SYNCING');
    }

    DomainEventBus.publish('product.sync.requested', {
      productId,
      platforms: mappings.map((m) => m.platform),
      tenantId,
      timestamp: new Date(),
    });
  }

  private static async deleteProductMappings(
    tenantId: string,
    productId: string
  ): Promise<void> {
    await db(this.MAPPING_TABLE)
      .where({ tenant_id: tenantId, master_product_id: productId })
      .delete();

    await db('cf_product')
      .where({ tenant_id: tenantId, id: productId })
      .update({ status: 'DELETED', updated_at: new Date() });
  }

  private static rowToMapping(row: any): PlatformMapping {
    return {
      id: row.id,
      tenantId: row.tenant_id,
      masterProductId: row.master_product_id,
      masterPlatform: row.master_platform,
      platform: row.platform,
      platformProductId: row.platform_product_id,
      platformSku: row.platform_sku,
      status: row.status,
      lastSyncAt: row.last_sync_at,
      syncError: row.sync_error,
      metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
      createdAt: row.created_at,
      updatedAt: row.updated_at,
    };
  }

  private static generateId(): string {
    return `mpm_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
}
