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

export interface IndependentSite {
  id: string;
  tenantId: string;
  name: string;
  domain: string;
  platform: 'SHOPIFY' | 'WOOCOMMERCE' | 'MAGENTO' | 'CUSTOM';
  status: 'ACTIVE' | 'INACTIVE' | 'MAINTENANCE' | 'ERROR';
  config: Record<string, any>;
  theme: Record<string, any>;
  paymentGateways: string[];
  shippingMethods: string[];
  analytics: Record<string, any>;
  seoConfig: Record<string, any>;
  createdAt: string;
  updatedAt: string;
}

export interface IndependentSiteProduct {
  id: string;
  siteId: string;
  productId: string;
  syncStatus: 'SYNCED' | 'PENDING' | 'FAILED';
  lastSyncAt?: string;
  error?: string;
}

export interface IndependentSiteOrder {
  id: string;
  siteId: string;
  orderId: string;
  status: string;
  totalAmount: number;
  currency: string;
  createdAt: string;
}

export class IndependentSiteService {
  private static SITE_TABLE = 'cf_independent_site';
  private static PRODUCT_TABLE = 'cf_independent_site_product';
  private static ORDER_TABLE = 'cf_independent_site_order';

  static async initTables(): Promise<void> {
    await this.initSiteTable();
    await this.initProductTable();
    await this.initOrderTable();
  }

  private static async initSiteTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.SITE_TABLE);
    if (!hasTable) {
      await db.schema.createTable(this.SITE_TABLE, (table) => {
        table.string('id', 64).primary();
        table.string('tenant_id', 64).notNullable();
        table.string('name', 256).notNullable();
        table.string('domain', 256).notNullable();
        table.enum('platform', ['SHOPIFY', 'WOOCOMMERCE', 'MAGENTO', 'CUSTOM']).defaultTo('CUSTOM');
        table.enum('status', ['ACTIVE', 'INACTIVE', 'MAINTENANCE', 'ERROR']).defaultTo('ACTIVE');
        table.json('config');
        table.json('theme');
        table.json('payment_gateways');
        table.json('shipping_methods');
        table.json('analytics');
        table.json('seo_config');
        table.timestamps(true, true);
        table.index(['tenant_id', 'status']);
        table.unique(['tenant_id', 'domain']);
      });
    }
  }

  private static async initProductTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.PRODUCT_TABLE);
    if (!hasTable) {
      await db.schema.createTable(this.PRODUCT_TABLE, (table) => {
        table.string('id', 64).primary();
        table.string('site_id', 64).notNullable();
        table.string('product_id', 64).notNullable();
        table.enum('sync_status', ['SYNCED', 'PENDING', 'FAILED']).defaultTo('PENDING');
        table.timestamp('last_sync_at');
        table.text('error');
        table.timestamps(true, true);
        table.index(['site_id', 'product_id']);
        table.unique(['site_id', 'product_id']);
      });
    }
  }

  private static async initOrderTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.ORDER_TABLE);
    if (!hasTable) {
      await db.schema.createTable(this.ORDER_TABLE, (table) => {
        table.string('id', 64).primary();
        table.string('site_id', 64).notNullable();
        table.string('order_id', 64).notNullable();
        table.string('status', 64);
        table.decimal('total_amount', 10, 2);
        table.string('currency', 8);
        table.timestamp('created_at');
        table.index(['site_id', 'order_id']);
      });
    }
  }

  static async listSites(tenantId: string): Promise<IndependentSite[]> {
    return db(this.SITE_TABLE).where('tenant_id', tenantId).orderBy('created_at', 'desc');
  }

  static async getSiteById(id: string): Promise<IndependentSite | null> {
    const site = await db(this.SITE_TABLE).where({ id }).first();
    return site || null;
  }

  static async createSite(tenantId: string, data: {
    name: string;
    domain: string;
    platform?: 'SHOPIFY' | 'WOOCOMMERCE' | 'MAGENTO' | 'CUSTOM';
    config?: Record<string, any>;
    theme?: Record<string, any>;
  }): Promise<IndependentSite> {
    const id = this.generateId('site');
    const now = new Date().toISOString();
    const site: IndependentSite = {
      id,
      tenantId,
      name: data.name,
      domain: data.domain,
      platform: data.platform || 'CUSTOM',
      status: 'ACTIVE',
      config: data.config || {},
      theme: data.theme || {},
      paymentGateways: [],
      shippingMethods: [],
      analytics: {},
      seoConfig: {},
      createdAt: now,
      updatedAt: now,
    };
    await db(this.SITE_TABLE).insert({
      id: site.id,
      tenant_id: site.tenantId,
      name: site.name,
      domain: site.domain,
      platform: site.platform,
      status: site.status,
      config: JSON.stringify(site.config),
      theme: JSON.stringify(site.theme),
      payment_gateways: JSON.stringify(site.paymentGateways),
      shipping_methods: JSON.stringify(site.shippingMethods),
      analytics: JSON.stringify(site.analytics),
      seo_config: JSON.stringify(site.seoConfig),
      created_at: site.createdAt,
      updated_at: site.updatedAt,
    });
    await DomainEventBus.publish('independent_site.created', { siteId: id, tenantId });
    return site;
  }

  static async updateSite(id: string, data: Partial<IndependentSite>): Promise<IndependentSite> {
    const updateData: Record<string, any> = { updated_at: new Date().toISOString() };
    if (data.name) updateData.name = data.name;
    if (data.domain) updateData.domain = data.domain;
    if (data.status) updateData.status = data.status;
    if (data.config) updateData.config = JSON.stringify(data.config);
    if (data.theme) updateData.theme = JSON.stringify(data.theme);
    if (data.paymentGateways) updateData.payment_gateways = JSON.stringify(data.paymentGateways);
    if (data.shippingMethods) updateData.shipping_methods = JSON.stringify(data.shippingMethods);
    if (data.analytics) updateData.analytics = JSON.stringify(data.analytics);
    if (data.seoConfig) updateData.seo_config = JSON.stringify(data.seoConfig);
    await db(this.SITE_TABLE).where({ id }).update(updateData);
    const site = await this.getSiteById(id);
    await DomainEventBus.publish('independent_site.updated', { siteId: id });
    return site!;
  }

  static async deleteSite(id: string): Promise<void> {
    await db(this.PRODUCT_TABLE).where('site_id', id).delete();
    await db(this.ORDER_TABLE).where('site_id', id).delete();
    await db(this.SITE_TABLE).where({ id }).delete();
    await DomainEventBus.publish('independent_site.deleted', { siteId: id });
  }

  static async syncProducts(siteId: string, productIds: string[]): Promise<IndependentSiteProduct[]> {
    const results: IndependentSiteProduct[] = [];
    for (const productId of productIds) {
      const id = this.generateId('prod');
      const record: IndependentSiteProduct = {
        id,
        siteId,
        productId,
        syncStatus: 'SYNCED',
        lastSyncAt: new Date().toISOString(),
      };
      await db(this.PRODUCT_TABLE)
        .insert({
          id: record.id,
          site_id: record.siteId,
          product_id: record.productId,
          sync_status: record.syncStatus,
          last_sync_at: record.lastSyncAt,
        })
        .onConflict(['site_id', 'product_id'])
        .merge();
      results.push(record);
    }
    await DomainEventBus.publish('independent_site.products_synced', { siteId, count: productIds.length });
    return results;
  }

  static async getSiteProducts(siteId: string): Promise<IndependentSiteProduct[]> {
    return db(this.PRODUCT_TABLE).where('site_id', siteId);
  }

  static async getSiteOrders(siteId: string, filters?: { status?: string }): Promise<IndependentSiteOrder[]> {
    let query = db(this.ORDER_TABLE).where('site_id', siteId);
    if (filters?.status) query = query.where('status', filters.status);
    return query.orderBy('created_at', 'desc');
  }

  static async getSiteAnalytics(siteId: string, timeRange: { start: string; end: string }): Promise<Record<string, any>> {
    const orders = await db(this.ORDER_TABLE)
      .where('site_id', siteId)
      .whereBetween('created_at', [timeRange.start, timeRange.end]);
    const totalRevenue = orders.reduce((sum, o) => sum + (o.total_amount || 0), 0);
    return {
      totalOrders: orders.length,
      totalRevenue,
      averageOrderValue: orders.length > 0 ? totalRevenue / orders.length : 0,
    };
  }

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