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

export interface PlatformIntegration {
  id: string;
  tenantId: string;
  platform: 'sellbrite' | 'shoplazza' | 'salesmartly' | 'amazon' | 'ebay' | 'shopify';
  credentials: Record<string, any>;
  status: 'connected' | 'disconnected' | 'error';
  lastSyncAt?: Date;
  createdAt: Date;
}

export interface InventorySyncRecord {
  id: string;
  tenantId: string;
  productId: string;
  platform: string;
  platformSku: string;
  quantity: number;
  syncStatus: 'success' | 'failed' | 'pending';
  syncError?: string;
  syncedAt: Date;
}

export interface MarketingIntegration {
  id: string;
  tenantId: string;
  platform: string;
  campaignId: string;
  config: Record<string, any>;
  metrics: Record<string, any>;
  createdAt: Date;
}

export class CrossBorderIntegrationService {
  private static INTEGRATION_TABLE = 'cf_platform_integration';
  private static SYNC_TABLE = 'cf_inventory_sync_record';
  private static MARKETING_TABLE = 'cf_marketing_integration';

  static async initTables(): Promise<void> {
    await this.initIntegrationTable();
    await this.initSyncTable();
    await this.initMarketingTable();
  }

  private static async initIntegrationTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.INTEGRATION_TABLE);
    if (!hasTable) {
      logger.info(`[CrossBorderIntegration] Creating ${this.INTEGRATION_TABLE} table...`);
      await db.schema.createTable(this.INTEGRATION_TABLE, (table) => {
        table.string('id', 36).primary();
        table.string('tenant_id', 36).notNullable().index();
        table.enum('platform', ['sellbrite', 'shoplazza', 'salesmartly', 'amazon', 'ebay', 'shopify']).notNullable();
        table.json('credentials');
        table.enum('status', ['connected', 'disconnected', 'error']).defaultTo('disconnected');
        table.datetime('last_sync_at');
        table.datetime('created_at').notNullable().defaultTo(db.fn.now());
        table.unique(['tenant_id', 'platform'], 'uk_tenant_platform');
      });
      logger.info(`[CrossBorderIntegration] Table ${this.INTEGRATION_TABLE} created`);
    }
  }

  private static async initSyncTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.SYNC_TABLE);
    if (!hasTable) {
      logger.info(`[CrossBorderIntegration] Creating ${this.SYNC_TABLE} table...`);
      await db.schema.createTable(this.SYNC_TABLE, (table) => {
        table.string('id', 36).primary();
        table.string('tenant_id', 36).notNullable().index();
        table.string('product_id', 36).notNullable().index();
        table.string('platform', 32).notNullable();
        table.string('platform_sku', 64).notNullable();
        table.integer('quantity').notNullable();
        table.enum('sync_status', ['success', 'failed', 'pending']).defaultTo('pending');
        table.text('sync_error');
        table.datetime('synced_at').notNullable().defaultTo(db.fn.now());
        table.index(['tenant_id', 'platform', 'product_id'], 'idx_tenant_platform_product');
      });
      logger.info(`[CrossBorderIntegration] Table ${this.SYNC_TABLE} created`);
    }
  }

  private static async initMarketingTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.MARKETING_TABLE);
    if (!hasTable) {
      logger.info(`[CrossBorderIntegration] Creating ${this.MARKETING_TABLE} table...`);
      await db.schema.createTable(this.MARKETING_TABLE, (table) => {
        table.string('id', 36).primary();
        table.string('tenant_id', 36).notNullable().index();
        table.string('platform', 32).notNullable();
        table.string('campaign_id', 64).notNullable();
        table.json('config');
        table.json('metrics');
        table.datetime('created_at').notNullable().defaultTo(db.fn.now());
      });
      logger.info(`[CrossBorderIntegration] Table ${this.MARKETING_TABLE} created`);
    }
  }

  static async integrateSellbrite(
    tenantId: string,
    credentials: { apiKey: string; accountId: string }
  ): Promise<PlatformIntegration> {
    return this.integratePlatform(tenantId, 'sellbrite', credentials);
  }

  static async integrateShoplazza(
    tenantId: string,
    credentials: { apiKey: string; storeId: string }
  ): Promise<PlatformIntegration> {
    return this.integratePlatform(tenantId, 'shoplazza', credentials);
  }

  static async integrateSaleSmartly(
    tenantId: string,
    credentials: { apiKey: string; workspaceId: string }
  ): Promise<PlatformIntegration> {
    return this.integratePlatform(tenantId, 'salesmartly', credentials);
  }

  private static async integratePlatform(
    tenantId: string,
    platform: PlatformIntegration['platform'],
    credentials: Record<string, any>
  ): Promise<PlatformIntegration> {
    const existing = await db(this.INTEGRATION_TABLE)
      .where({ tenant_id: tenantId, platform })
      .first();

    const id = existing?.id || this.generateId();
    const integration: PlatformIntegration = {
      id,
      tenantId,
      platform,
      credentials,
      status: 'connected',
      lastSyncAt: new Date(),
      createdAt: existing?.created_at ? new Date(existing.created_at) : new Date(),
    };

    if (existing) {
      await db(this.INTEGRATION_TABLE)
        .where({ id: existing.id })
        .update({
          credentials: JSON.stringify(credentials),
          status: 'connected',
          last_sync_at: integration.lastSyncAt,
        });
    } else {
      await db(this.INTEGRATION_TABLE).insert({
        id: integration.id,
        tenant_id: integration.tenantId,
        platform: integration.platform,
        credentials: JSON.stringify(integration.credentials),
        status: integration.status,
        last_sync_at: integration.lastSyncAt,
        created_at: integration.createdAt,
      });
    }

    await DomainEventBus.publish('platform.integrated', {
      tenantId,
      platform,
      integrationId: id,
      timestamp: new Date(),
    });

    logger.info(`[CrossBorderIntegration] Integrated platform ${platform} for tenant ${tenantId}`);
    return integration;
  }

  static async syncInventoryToPlatforms(
    tenantId: string,
    inventoryData: Array<{
      productId: string;
      sku: string;
      quantity: number;
    }>
  ): Promise<InventorySyncRecord[]> {
    const integrations = await db(this.INTEGRATION_TABLE)
      .where({ tenant_id: tenantId, status: 'connected' })
      .select('*');

    const records: InventorySyncRecord[] = [];

    for (const integration of integrations) {
      for (const item of inventoryData) {
        const record: InventorySyncRecord = {
          id: this.generateId(),
          tenantId,
          productId: item.productId,
          platform: integration.platform,
          platformSku: item.sku,
          quantity: item.quantity,
          syncStatus: 'success',
          syncedAt: new Date(),
        };

        await db(this.SYNC_TABLE).insert({
          id: record.id,
          tenant_id: record.tenantId,
          product_id: record.productId,
          platform: record.platform,
          platform_sku: record.platformSku,
          quantity: record.quantity,
          sync_status: record.syncStatus,
          sync_error: record.syncError,
          synced_at: record.syncedAt,
        });

        records.push(record);
      }
    }

    await DomainEventBus.publish('inventory.synced', {
      tenantId,
      itemCount: inventoryData.length,
      platformCount: integrations.length,
      timestamp: new Date(),
    });

    logger.info(`[CrossBorderIntegration] Synced ${records.length} inventory records across ${integrations.length} platforms`);
    return records;
  }

  static async integrateMarketing(
    tenantId: string,
    params: { platform: string; campaignId: string; config: Record<string, any> }
  ): Promise<MarketingIntegration> {
    const id = this.generateId();
    const integration: MarketingIntegration = {
      id,
      tenantId,
      platform: params.platform,
      campaignId: params.campaignId,
      config: params.config,
      metrics: {},
      createdAt: new Date(),
    };

    await db(this.MARKETING_TABLE).insert({
      id: integration.id,
      tenant_id: integration.tenantId,
      platform: integration.platform,
      campaign_id: integration.campaignId,
      config: JSON.stringify(integration.config),
      metrics: JSON.stringify(integration.metrics),
      created_at: integration.createdAt,
    });

    await DomainEventBus.publish('marketing.integrated', {
      tenantId,
      platform: params.platform,
      campaignId: params.campaignId,
      timestamp: new Date(),
    });

    logger.info(`[CrossBorderIntegration] Integrated marketing campaign ${params.campaignId} on ${params.platform}`);
    return integration;
  }

  static async getIntegrationStatus(
    tenantId: string,
    platform?: string
  ): Promise<PlatformIntegration[]> {
    const query = db(this.INTEGRATION_TABLE).where({ tenant_id: tenantId });

    if (platform) {
      query.andWhere({ platform });
    }

    const rows = await query.select('*');
    return rows.map((row) => this.rowToIntegration(row));
  }

  static async disconnectPlatform(
    tenantId: string,
    platform: string
  ): Promise<{ success: boolean; message: string }> {
    await db(this.INTEGRATION_TABLE)
      .where({ tenant_id: tenantId, platform })
      .update({ status: 'disconnected' });

    await DomainEventBus.publish('platform.disconnected', {
      tenantId,
      platform,
      timestamp: new Date(),
    });

    logger.info(`[CrossBorderIntegration] Disconnected platform ${platform}`);
    return { success: true, message: `Platform ${platform} disconnected` };
  }

  private static rowToIntegration(row: any): PlatformIntegration {
    return {
      id: row.id,
      tenantId: row.tenant_id,
      platform: row.platform,
      credentials: row.credentials ? JSON.parse(row.credentials) : {},
      status: row.status,
      lastSyncAt: row.last_sync_at,
      createdAt: row.created_at,
    };
  }

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