import { logger } from '../../utils/logger';
import db from '../../config/database';
import type { Knex } from 'knex';

export interface ReconciliationRecord {
  id: string;
  tenantId: string;
  shopId: string;
  platform: string;
  periodStart: Date;
  periodEnd: Date;
  expectedAmount: number;
  actualAmount: number;
  difference: number;
  status: ReconciliationStatus;
  exceptionDetails: string;
  resolutionAction?: string;
  traceId: string;
  taskId: string;
  businessType: 'TOC' | 'TOB';
  createdAt: Date;
  updatedAt: Date;
}

export interface CreateReconciliationParams {
  tenantId: string;
  shopId: string;
  platform: string;
  periodStart: Date;
  periodEnd: Date;
  expectedAmount: number;
  actualAmount: number;
  traceId: string;
  taskId: string;
  businessType: 'TOC' | 'TOB';
}

export interface ReconciliationResult {
  success: boolean;
  record: ReconciliationRecord;
  message: string;
}

export enum ReconciliationStatus {
  PENDING = 'PENDING',
  PROCESSING = 'PROCESSING',
  COMPLETED = 'COMPLETED',
  EXCEPTION = 'EXCEPTION',
  RESOLVED = 'RESOLVED'
}

export interface ReconciliationData {
  id: string;
  tenantId: string;
  shopId: string;
  platform: string;
  periodStart: Date;
  periodEnd: Date;
  expectedAmount: number;
  actualAmount: number;
  difference: number;
  status: ReconciliationStatus;
  exceptionDetails: string;
  resolutionAction?: string;
  traceId: string;
  taskId: string;
  businessType: 'TOC' | 'TOB';
  createdAt: Date;
  updatedAt: Date;
}

export interface ReconciliationSummary {
  platform: string;
  totalReconciliations: number;
  completedReconciliations: number;
  exceptionReconciliations: number;
  totalExpectedAmount: number;
  totalActualAmount: number;
  totalDifference: number;
  periodStart: Date;
  periodEnd: Date;
}

export class ReconciliationService {
  /**
   * 初始化数据库表
   */
  static async initTable() {
    logger.info('🚀 ReconciliationService table initialized');
    
    const hasTable = await db.schema.hasTable('cf_reconciliation');
    if (!hasTable) {
      await db.schema.createTable('cf_reconciliation', (table: Knex.CreateTableBuilder) => {
        table.string('id').primary();
        table.string('tenantId').notNullable();
        table.string('shopId').notNullable();
        table.string('platform').notNullable();
        table.dateTime('periodStart').notNullable();
        table.dateTime('periodEnd').notNullable();
        table.decimal('expectedAmount', 10, 2).notNullable();
        table.decimal('actualAmount', 10, 2).notNullable();
        table.decimal('difference', 10, 2).notNullable();
        table.enum('status', Object.values(ReconciliationStatus)).notNullable();
        table.text('exceptionDetails');
        table.text('resolutionAction');
        table.string('traceId').notNullable();
        table.string('taskId').notNullable();
        table.enum('businessType', ['TOC', 'TOB']).notNullable();
        table.timestamp('createdAt').defaultTo(db.fn.now());
        table.timestamp('updatedAt').defaultTo(db.fn.now());
        
        table.index(['tenantId', 'shopId']);
        table.index(['platform', 'periodStart', 'periodEnd']);
        table.index(['status']);
      });
      logger.info('✅ cf_reconciliation table created');
    }
  }

  /**
   * 创建对账记录
   */
  static async createReconciliation(params: CreateReconciliationParams): Promise<ReconciliationResult> {
    logger.info(`[ReconciliationService] Creating reconciliation for platform: ${params.platform}`, { traceId: params.traceId });
    
    const difference = params.expectedAmount - params.actualAmount;
    const status = Math.abs(difference) < 0.01 ? ReconciliationStatus.COMPLETED : ReconciliationStatus.EXCEPTION;
    const exceptionDetails = status === ReconciliationStatus.EXCEPTION ? `Amount mismatch: expected ${params.expectedAmount}, actual ${params.actualAmount}, difference ${difference}` : '';
    
    const record: ReconciliationData = {
      id: 'reconciliation_' + Date.now(),
      tenantId: params.tenantId,
      shopId: params.shopId,
      platform: params.platform,
      periodStart: params.periodStart,
      periodEnd: params.periodEnd,
      expectedAmount: params.expectedAmount,
      actualAmount: params.actualAmount,
      difference,
      status,
      exceptionDetails,
      traceId: params.traceId,
      taskId: params.taskId,
      businessType: params.businessType,
      createdAt: new Date(),
      updatedAt: new Date()
    };
    
    try {
      await db('cf_reconciliation').insert(record);
      logger.info(`[ReconciliationService] Reconciliation created: ${record.id}`, { traceId: params.traceId });
    } catch (error) {
      logger.error(`[ReconciliationService] Failed to create reconciliation: ${error}`, { traceId: params.traceId });
      throw error;
    }
    
    return {
      success: true,
      record: record as ReconciliationRecord,
      message: status === ReconciliationStatus.COMPLETED ? 'Reconciliation completed successfully' : 'Reconciliation completed with exceptions'
    };
  }

  /**
   * 获取对账记录列表
   */
  static async getReconciliations(tenantId: string, shopId: string, status?: ReconciliationStatus, platform?: string, startDate?: Date, endDate?: Date, traceId: string = ''): Promise<ReconciliationData[]> {
    logger.info(`[ReconciliationService] Getting reconciliations for tenant: ${tenantId}, shop: ${shopId}`, { traceId });
    
    let query = db('cf_reconciliation').where({ tenantId, shopId });
    
    if (status) {
      query = query.where({ status });
    }
    
    if (platform) {
      query = query.where({ platform });
    }
    
    if (startDate) {
      query = query.where('periodStart', '>=', startDate);
    }
    
    if (endDate) {
      query = query.where('periodEnd', '<=', endDate);
    }
    
    try {
      const records = await query.orderBy('createdAt', 'desc');
      return records;
    } catch (error) {
      logger.error(`[ReconciliationService] Failed to get reconciliations: ${error}`, { traceId });
      return [];
    }
  }

  /**
   * 获取对账记录详情
   */
  static async getReconciliationById(id: string, traceId: string = ''): Promise<ReconciliationData | null> {
    logger.info(`[ReconciliationService] Getting reconciliation: ${id}`, { traceId });
    
    try {
      const record = await db('cf_reconciliation').where({ id }).first();
      return record || null;
    } catch (error) {
      logger.error(`[ReconciliationService] Failed to get reconciliation: ${error}`, { traceId });
      return null;
    }
  }

  /**
   * 处理异常对账
   */
  static async handleException(id: string, action: string, traceId: string = ''): Promise<ReconciliationResult> {
    logger.info(`[ReconciliationService] Handling exception for reconciliation: ${id}, action: ${action}`, { traceId });
    
    try {
      const record = await db('cf_reconciliation').where({ id }).first();
      if (!record) {
        throw new Error(`Reconciliation not found: ${id}`);
      }
      
      const updatedRecord = {
        ...record,
        status: ReconciliationStatus.RESOLVED,
        resolutionAction: action,
        updatedAt: new Date()
      };
      
      await db('cf_reconciliation').where({ id }).update(updatedRecord);
      logger.info(`[ReconciliationService] Exception handled for reconciliation: ${id}`, { traceId });
      
      return {
        success: true,
        record: updatedRecord as ReconciliationRecord,
        message: 'Exception handled successfully'
      };
    } catch (error) {
      logger.error(`[ReconciliationService] Failed to handle exception: ${error}`, { traceId });
      throw error;
    }
  }

  /**
   * 批量对账
   */
  static async batchReconciliation(tenantId: string, shopId: string, platforms: string[], periodStart: Date, periodEnd: Date, traceId: string = ''): Promise<ReconciliationResult[]> {
    logger.info(`[ReconciliationService] Batch reconciliation for platforms: ${platforms.join(', ')}`, { traceId });
    
    const results: ReconciliationResult[] = [];
    
    for (const platform of platforms) {
      try {
        // 模拟获取平台数据
        const expectedAmount = Math.random() * 10000;
        const actualAmount = expectedAmount - (Math.random() * 100);
        
        const params: CreateReconciliationParams = {
          tenantId,
          shopId,
          platform,
          periodStart,
          periodEnd,
          expectedAmount,
          actualAmount,
          traceId,
          taskId: 'batch_' + Date.now(),
          businessType: 'TOC'
        };
        
        const result = await this.createReconciliation(params);
        results.push(result);
      } catch (error) {
        logger.error(`[ReconciliationService] Failed to reconcile platform ${platform}: ${error}`, { traceId });
        results.push({
          success: false,
          record: {} as ReconciliationRecord,
          message: `Failed to reconcile platform ${platform}: ${error}`
        });
      }
    }
    
    return results;
  }

  /**
   * 获取对账汇总
   */
  static async getReconciliationSummary(tenantId: string, shopId: string, periodStart: Date, periodEnd: Date, traceId: string = ''): Promise<ReconciliationSummary[]> {
    logger.info(`[ReconciliationService] Getting reconciliation summary`, { traceId });
    
    try {
      const summaries = await db('cf_reconciliation')
        .select('platform')
        .sum('expectedAmount as totalExpectedAmount')
        .sum('actualAmount as totalActualAmount')
        .sum('difference as totalDifference')
        .count('id as totalReconciliations')
        .count(db.raw('CASE WHEN status = ? THEN 1 END', [ReconciliationStatus.COMPLETED]))
          .as('completedReconciliations')
        .count(db.raw('CASE WHEN status = ? THEN 1 END', [ReconciliationStatus.EXCEPTION]))
          .as('exceptionReconciliations')
        .where({ tenantId, shopId })
        .where('periodStart', '>=', periodStart)
        .where('periodEnd', '<=', periodEnd)
        .groupBy('platform');
      
      return summaries.map((summary: any) => ({
        platform: summary.platform,
        totalReconciliations: parseInt(summary.totalReconciliations),
        completedReconciliations: parseInt(summary.completedReconciliations || 0),
        exceptionReconciliations: parseInt(summary.exceptionReconciliations || 0),
        totalExpectedAmount: parseFloat(summary.totalExpectedAmount || 0),
        totalActualAmount: parseFloat(summary.totalActualAmount || 0),
        totalDifference: parseFloat(summary.totalDifference || 0),
        periodStart,
        periodEnd
      }));
    } catch (error) {
      logger.error(`[ReconciliationService] Failed to get reconciliation summary: ${error}`, { traceId });
      return [];
    }
  }

  /**
   * 自动对账任务
   */
  static async autoReconciliationTask(tenantId: string, shopId: string, platforms: string[], traceId: string = ''): Promise<void> {
    logger.info(`[ReconciliationService] Starting auto reconciliation task`, { traceId });
    
    const periodEnd = new Date();
    const periodStart = new Date();
    periodStart.setDate(periodEnd.getDate() - 1);
    
    await this.batchReconciliation(tenantId, shopId, platforms, periodStart, periodEnd, traceId);
    logger.info(`[ReconciliationService] Auto reconciliation task completed`, { traceId });
  }

  /**
   * 导出对账报告
   */
  static async exportReconciliationReport(tenantId: string, shopId: string, periodStart: Date, periodEnd: Date, traceId: string = ''): Promise<Buffer> {
    logger.info(`[ReconciliationService] Exporting reconciliation report`, { traceId });
    
    const reconciliations = await this.getReconciliations(tenantId, shopId, undefined, undefined, periodStart, periodEnd, traceId);
    
    // 生成CSV格式报告
    const headers = ['ID', 'Platform', 'Period Start', 'Period End', 'Expected Amount', 'Actual Amount', 'Difference', 'Status', 'Exception Details', 'Business Type', 'Created At'];
    const rows = reconciliations.map(r => [
      r.id,
      r.platform,
      r.periodStart.toISOString(),
      r.periodEnd.toISOString(),
      r.expectedAmount,
      r.actualAmount,
      r.difference,
      r.status,
      r.exceptionDetails || '',
      r.businessType,
      r.createdAt.toISOString()
    ]);
    
    const csvContent = [
      headers.join(','),
      ...rows.map(row => row.join(','))
    ].join('\n');
    
    return Buffer.from(csvContent, 'utf-8');
  }
}
