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

export interface BatchOrderSubmitPayload {
  tenantId: string;
  shopId: string;
  taskId: string;
  traceId: string;
  businessType: 'TOC' | 'TOB';
  platformAccount: string;
  orders: BatchOrderItem[];
}

export interface BatchOrderItem {
  orderId: string;
  productId: string;
  productName: string;
  quantity: number;
  unitPrice: number;
  customerId: string;
  customerName: string;
  shippingAddress: {
    country: string;
    province: string;
    city: string;
    address: string;
    postalCode: string;
    recipientName: string;
    recipientPhone: string;
  };
  notes?: string;
}

export interface BatchOrderSubmitResult {
  success: boolean;
  submittedCount: number;
  failedCount: number;
  results: OrderSubmitResult[];
  batchId: string;
  submittedAt: Date;
}

export interface OrderSubmitResult {
  orderId: string;
  success: boolean;
  platformOrderId?: string;
  errorMessage?: string;
}

export interface ContractSyncPayload {
  tenantId: string;
  shopId: string;
  taskId: string;
  traceId: string;
  businessType: 'TOC' | 'TOB';
  platformAccount: string;
  contractId: string;
}

export interface ContractSyncResult {
  success: boolean;
  contractId: string;
  status: 'DRAFT' | 'PENDING_SIGNATURE' | 'SIGNED' | 'ACTIVE' | 'EXPIRED' | 'TERMINATED';
  signedAt?: Date;
  expiresAt?: Date;
  parties: ContractParty[];
  terms: ContractTerm[];
  lastSyncedAt: Date;
}

export interface ContractParty {
  partyId: string;
  partyName: string;
  partyType: 'BUYER' | 'SELLER';
  signedAt?: Date;
  signatureStatus: 'PENDING' | 'SIGNED' | 'REJECTED';
}

export interface ContractTerm {
  termId: string;
  termType: 'PAYMENT' | 'DELIVERY' | 'WARRANTY' | 'PRICING' | 'OTHER';
  description: string;
  value?: string;
  unit?: string;
}

export default class B2BTradePlugin implements BizPlugin {
  name = 'B2BTradePlugin';
  version = '1.0.0';
  description = 'B2B trade automation plugin for batch order submission and contract synchronization';

  async onLoad(): Promise<void> {
    logger.info(`[${this.name}] B2B Trade Plugin initialized`);
    await this.initializeTables();
  }

  async onUnload(): Promise<void> {
    logger.info(`[${this.name}] B2B Trade Plugin unloaded`);
  }

  private async initializeTables(): Promise<void> {
    if (!(await db.schema.hasTable('cf_batch_order_submissions'))) {
      await db.schema.createTable('cf_batch_order_submissions', (table) => {
        table.string('id').primary();
        table.string('tenant_id').notNullable();
        table.string('shop_id').notNullable();
        table.string('task_id').notNullable();
        table.string('trace_id').notNullable();
        table.enum('business_type', ['TOC', 'TOB']).notNullable();
        table.string('platform_account').notNullable();
        table.integer('total_orders').notNullable();
        table.integer('submitted_count').defaultTo(0);
        table.integer('failed_count').defaultTo(0);
        table.enum('status', ['PENDING', 'PROCESSING', 'COMPLETED', 'FAILED']).defaultTo('PENDING');
        table.timestamp('submitted_at');
        table.timestamp('created_at').defaultTo(db.fn.now());
        table.timestamp('updated_at').defaultTo(db.fn.now());
        
        table.index(['tenant_id', 'shop_id']);
        table.index(['status']);
        table.index(['created_at']);
      });
      logger.info(`[${this.name}] Created cf_batch_order_submissions table`);
    }

    if (!(await db.schema.hasTable('cf_batch_order_items'))) {
      await db.schema.createTable('cf_batch_order_items', (table) => {
        table.string('id').primary();
        table.string('batch_id').notNullable();
        table.string('order_id').notNullable();
        table.string('product_id').notNullable();
        table.string('product_name');
        table.integer('quantity').notNullable();
        table.decimal('unit_price', 10, 2).notNullable();
        table.string('customer_id').notNullable();
        table.string('customer_name');
        table.string('platform_order_id');
        table.enum('status', ['PENDING', 'SUBMITTED', 'FAILED']).defaultTo('PENDING');
        table.text('error_message');
        table.timestamp('submitted_at');
        table.timestamp('created_at').defaultTo(db.fn.now());
        
        table.foreign('batch_id').references('cf_batch_order_submissions.id');
        table.index(['batch_id']);
        table.index(['order_id']);
        table.index(['status']);
      });
      logger.info(`[${this.name}] Created cf_batch_order_items table`);
    }

    if (!(await db.schema.hasTable('cf_contract_sync_logs'))) {
      await db.schema.createTable('cf_contract_sync_logs', (table) => {
        table.string('id').primary();
        table.string('tenant_id').notNullable();
        table.string('shop_id').notNullable();
        table.string('task_id').notNullable();
        table.string('trace_id').notNullable();
        table.enum('business_type', ['TOC', 'TOB']).notNullable();
        table.string('platform_account').notNullable();
        table.string('contract_id').notNullable();
        table.enum('status', ['DRAFT', 'PENDING_SIGNATURE', 'SIGNED', 'ACTIVE', 'EXPIRED', 'TERMINATED']);
        table.timestamp('signed_at');
        table.timestamp('expires_at');
        table.json('parties');
        table.json('terms');
        table.timestamp('synced_at').defaultTo(db.fn.now());
        table.timestamp('created_at').defaultTo(db.fn.now());
        
        table.index(['tenant_id', 'shop_id']);
        table.index(['contract_id']);
        table.index(['synced_at']);
      });
      logger.info(`[${this.name}] Created cf_contract_sync_logs table`);
    }
  }

  hooks = {
    'b2b:batch_order_submit': async (payload: BatchOrderSubmitPayload): Promise<BatchOrderSubmitResult> => {
      const { tenantId, shopId, taskId, traceId, businessType, platformAccount, orders } = payload;
      
      logger.info(`[${this.name}] Processing batch order submission - tenantId: ${tenantId}, shopId: ${shopId}, orderCount: ${orders.length}, traceId: ${traceId}`);

      const batchId = `BATCH-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
      const results: OrderSubmitResult[] = [];
      let submittedCount = 0;
      let failedCount = 0;

      try {
        await db('cf_batch_order_submissions').insert({
          id: batchId,
          tenant_id: tenantId,
          shop_id: shopId,
          task_id: taskId,
          trace_id: traceId,
          business_type: businessType,
          platform_account: platformAccount,
          total_orders: orders.length,
          submitted_count: 0,
          failed_count: 0,
          status: 'PROCESSING',
        });

        for (const order of orders) {
          try {
            const platformOrderId = await this.submitOrderToPlatform(platformAccount, order, traceId);
            
            results.push({
              orderId: order.orderId,
              success: true,
              platformOrderId,
            });
            submittedCount++;

            await db('cf_batch_order_items').insert({
              id: `${batchId}-${order.orderId}`,
              batch_id: batchId,
              order_id: order.orderId,
              product_id: order.productId,
              product_name: order.productName,
              quantity: order.quantity,
              unit_price: order.unitPrice,
              customer_id: order.customerId,
              customer_name: order.customerName,
              platform_order_id: platformOrderId,
              status: 'SUBMITTED',
              submitted_at: new Date(),
            });
          } catch (error: any) {
            logger.error(`[${this.name}] Failed to submit order ${order.orderId}: ${error.message}`);
            
            results.push({
              orderId: order.orderId,
              success: false,
              errorMessage: error.message,
            });
            failedCount++;

            await db('cf_batch_order_items').insert({
              id: `${batchId}-${order.orderId}`,
              batch_id: batchId,
              order_id: order.orderId,
              product_id: order.productId,
              product_name: order.productName,
              quantity: order.quantity,
              unit_price: order.unitPrice,
              customer_id: order.customerId,
              customer_name: order.customerName,
              status: 'FAILED',
              error_message: error.message,
            });
          }
        }

        await db('cf_batch_order_submissions')
          .where('id', batchId)
          .update({
            submitted_count: submittedCount,
            failed_count: failedCount,
            status: failedCount === 0 ? 'COMPLETED' : 'COMPLETED',
            submitted_at: new Date(),
            updated_at: new Date(),
          });

        logger.info(`[${this.name}] Batch order submission completed - batchId: ${batchId}, submitted: ${submittedCount}, failed: ${failedCount}`);

        return {
          success: true,
          submittedCount,
          failedCount,
          results,
          batchId,
          submittedAt: new Date(),
        };
      } catch (error: any) {
        logger.error(`[${this.name}] Batch order submission failed - batchId: ${batchId}, error: ${error.message}`);
        
        await db('cf_batch_order_submissions')
          .where('id', batchId)
          .update({
            status: 'FAILED',
            updated_at: new Date(),
          });

        throw error;
      }
    },

    'b2b:contract_sync': async (payload: ContractSyncPayload): Promise<ContractSyncResult> => {
      const { tenantId, shopId, taskId, traceId, businessType, platformAccount, contractId } = payload;
      
      logger.info(`[${this.name}] Syncing contract status - contractId: ${contractId}, tenantId: ${tenantId}, traceId: ${traceId}`);

      try {
        const contractData = await this.fetchContractFromPlatform(platformAccount, contractId, traceId);

        await db('cf_contract_sync_logs').insert({
          id: `CSL-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
          tenant_id: tenantId,
          shop_id: shopId,
          task_id: taskId,
          trace_id: traceId,
          business_type: businessType,
          platform_account: platformAccount,
          contract_id: contractId,
          status: contractData.status,
          signed_at: contractData.signedAt,
          expires_at: contractData.expiresAt,
          parties: JSON.stringify(contractData.parties),
          terms: JSON.stringify(contractData.terms),
          synced_at: new Date(),
        });

        logger.info(`[${this.name}] Contract sync completed - contractId: ${contractId}, status: ${contractData.status}`);

        return {
          success: true,
          contractId,
          status: contractData.status,
          signedAt: contractData.signedAt,
          expiresAt: contractData.expiresAt,
          parties: contractData.parties,
          terms: contractData.terms,
          lastSyncedAt: new Date(),
        };
      } catch (error: any) {
        logger.error(`[${this.name}] Contract sync failed - contractId: ${contractId}, error: ${error.message}`);
        throw error;
      }
    },
  };

  private async submitOrderToPlatform(
    platformAccount: string,
    order: BatchOrderItem,
    traceId: string
  ): Promise<string> {
    logger.info(`[${this.name}] Submitting order to platform - platformAccount: ${platformAccount}, orderId: ${order.orderId}, traceId: ${traceId}`);
    
    await new Promise(resolve => setTimeout(resolve, 100));
    
    const platformOrderId = `PO-${Date.now()}-${Math.random().toString(36).substr(2, 6).toUpperCase()}`;
    
    logger.info(`[${this.name}] Order submitted successfully - orderId: ${order.orderId}, platformOrderId: ${platformOrderId}`);
    
    return platformOrderId;
  }

  private async fetchContractFromPlatform(
    platformAccount: string,
    contractId: string,
    traceId: string
  ): Promise<{
    status: ContractSyncResult['status'];
    signedAt?: Date;
    expiresAt?: Date;
    parties: ContractParty[];
    terms: ContractTerm[];
  }> {
    logger.info(`[${this.name}] Fetching contract from platform - platformAccount: ${platformAccount}, contractId: ${contractId}, traceId: ${traceId}`);
    
    await new Promise(resolve => setTimeout(resolve, 100));
    
    return {
      status: 'ACTIVE',
      signedAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
      expiresAt: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000),
      parties: [
        {
          partyId: 'PARTY-001',
          partyName: 'Buyer Company Ltd.',
          partyType: 'BUYER',
          signedAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
          signatureStatus: 'SIGNED',
        },
        {
          partyId: 'PARTY-002',
          partyName: 'Seller Company Inc.',
          partyType: 'SELLER',
          signedAt: new Date(Date.now() - 6 * 24 * 60 * 60 * 1000),
          signatureStatus: 'SIGNED',
        },
      ],
      terms: [
        {
          termId: 'TERM-001',
          termType: 'PAYMENT',
          description: 'Net 30 payment terms',
          value: '30',
          unit: 'days',
        },
        {
          termId: 'TERM-002',
          termType: 'PRICING',
          description: 'Tiered pricing based on volume',
          value: '5-20',
          unit: '% discount',
        },
      ],
    };
  }
}
