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

export type AfterSalesType = 'REFUND' | 'RETURN' | 'EXCHANGE' | 'REPAIR' | 'CANCEL';
export type AfterSalesStatus = 
  | 'PENDING'
  | 'APPROVED'
  | 'REJECTED'
  | 'PROCESSING'
  | 'COMPLETED'
  | 'CLOSED';

export type RefundStatus = 
  | 'PENDING'
  | 'APPROVED'
  | 'PROCESSING'
  | 'COMPLETED'
  | 'FAILED'
  | 'CANCELLED';

export type ReturnStatus =
  | 'PENDING'
  | 'APPROVED'
  | 'IN_TRANSIT'
  | 'RECEIVED'
  | 'INSPECTING'
  | 'COMPLETED'
  | 'REJECTED';

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

export interface AfterSalesRequest {
  id: string;
  tenantId: string;
  orderId: string;
  type: AfterSalesType;
  status: AfterSalesStatus;
  reason: string;
  description?: string;
  items: AfterSalesItem[];
  customerId: string;
  customerName: string;
  customerEmail?: string;
  totalAmount: number;
  refundAmount?: number;
  approvedBy?: string;
  approvedAt?: Date;
  rejectedReason?: string;
  processedAt?: Date;
  completedAt?: Date;
  traceId: string;
  createdAt: Date;
  updatedAt: Date;
}

export interface AfterSalesItem {
  skuId: string;
  productId: string;
  productName: string;
  quantity: number;
  unitPrice: number;
  totalPrice: number;
  returnReason?: string;
  returnCondition?: 'NEW' | 'OPENED' | 'DAMAGED' | 'DEFECTIVE';
}

export interface RefundRecord {
  id: string;
  tenantId: string;
  orderId: string;
  afterSalesId?: string;
  amount: number;
  currency: string;
  status: RefundStatus;
  reason: string;
  refundMethod?: string;
  transactionId?: string;
  processedAt?: Date;
  completedAt?: Date;
  failedReason?: string;
  traceId: string;
  createdAt: Date;
  updatedAt: Date;
}

export interface ReturnRecord {
  id: string;
  tenantId: string;
  orderId: string;
  afterSalesId?: string;
  status: ReturnStatus;
  returnMethod: 'PICKUP' | 'DROP_OFF' | 'SHIPPING_LABEL';
  trackingNumber?: string;
  carrier?: string;
  receivedAt?: Date;
  inspectedAt?: Date;
  inspectionResult?: 'PASSED' | 'FAILED' | 'PARTIAL';
  inspectionNote?: string;
  restockQuantity?: number;
  disposalQuantity?: number;
  traceId: string;
  createdAt: Date;
  updatedAt: Date;
}

export interface AfterSalesResult {
  success: boolean;
  afterSalesId?: string;
  status: AfterSalesStatus;
  message: string;
  data?: Record<string, any>;
}

const AFTER_SALES_STATUS_TRANSITIONS: Record<AfterSalesStatus, AfterSalesStatus[]> = {
  'PENDING': ['APPROVED', 'REJECTED', 'CLOSED'],
  'APPROVED': ['PROCESSING', 'CLOSED'],
  'REJECTED': ['CLOSED'],
  'PROCESSING': ['COMPLETED', 'CLOSED'],
  'COMPLETED': [],
  'CLOSED': []
};

const RETURN_DEADLINE_DAYS = 30;
const REFUND_PROCESSING_DAYS = 7;

export class AfterSalesService {
  private static readonly AFTER_SALES_TABLE = 'cf_after_sales';
  private static readonly REFUND_TABLE = 'cf_refunds';
  private static readonly RETURN_TABLE = 'cf_returns';

  static async initTables(): Promise<void> {
    await this.initAfterSalesTable();
    await this.initRefundTable();
    await this.initReturnTable();
  }

  private static async initAfterSalesTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.AFTER_SALES_TABLE);
    if (!hasTable) {
      logger.info(`[AfterSales] Creating ${this.AFTER_SALES_TABLE} table...`);
      await db.schema.createTable(this.AFTER_SALES_TABLE, (table) => {
        table.string('id', 64).primary();
        table.string('tenant_id', 64).notNullable();
        table.string('order_id', 64).notNullable();
        table.enum('type', ['REFUND', 'RETURN', 'EXCHANGE', 'REPAIR', 'CANCEL']).notNullable();
        table.enum('status', ['PENDING', 'APPROVED', 'REJECTED', 'PROCESSING', 'COMPLETED', 'CLOSED']).defaultTo('PENDING');
        table.string('reason', 255).notNullable();
        table.text('description');
        table.json('items');
        table.string('customer_id', 64).notNullable();
        table.string('customer_name', 128);
        table.string('customer_email', 128);
        table.decimal('total_amount', 15, 2);
        table.decimal('refund_amount', 15, 2);
        table.string('approved_by', 64);
        table.datetime('approved_at');
        table.string('rejected_reason', 255);
        table.datetime('processed_at');
        table.datetime('completed_at');
        table.string('trace_id', 64);
        table.timestamps(true, true);

        table.index(['tenant_id', 'status'], 'idx_after_sales_tenant_status');
        table.index(['tenant_id', 'order_id'], 'idx_after_sales_tenant_order');
      });
      logger.info(`[AfterSales] Table ${this.AFTER_SALES_TABLE} created`);
    }
  }

  private static async initRefundTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.REFUND_TABLE);
    if (!hasTable) {
      logger.info(`[AfterSales] Creating ${this.REFUND_TABLE} table...`);
      await db.schema.createTable(this.REFUND_TABLE, (table) => {
        table.string('id', 64).primary();
        table.string('tenant_id', 64).notNullable();
        table.string('order_id', 64).notNullable();
        table.string('after_sales_id', 64);
        table.decimal('amount', 15, 2).notNullable();
        table.string('currency', 10).defaultTo('USD');
        table.enum('status', ['PENDING', 'APPROVED', 'PROCESSING', 'COMPLETED', 'FAILED', 'CANCELLED']).defaultTo('PENDING');
        table.string('reason', 255).notNullable();
        table.string('refund_method', 32);
        table.string('transaction_id', 128);
        table.datetime('processed_at');
        table.datetime('completed_at');
        table.string('failed_reason', 255);
        table.string('trace_id', 64);
        table.timestamps(true, true);

        table.index(['tenant_id', 'status'], 'idx_refund_tenant_status');
        table.index(['tenant_id', 'order_id'], 'idx_refund_tenant_order');
      });
      logger.info(`[AfterSales] Table ${this.REFUND_TABLE} created`);
    }
  }

  private static async initReturnTable(): Promise<void> {
    const hasTable = await db.schema.hasTable(this.RETURN_TABLE);
    if (!hasTable) {
      logger.info(`[AfterSales] Creating ${this.RETURN_TABLE} table...`);
      await db.schema.createTable(this.RETURN_TABLE, (table) => {
        table.string('id', 64).primary();
        table.string('tenant_id', 64).notNullable();
        table.string('order_id', 64).notNullable();
        table.string('after_sales_id', 64);
        table.enum('status', ['PENDING', 'APPROVED', 'IN_TRANSIT', 'RECEIVED', 'INSPECTING', 'COMPLETED', 'REJECTED']).defaultTo('PENDING');
        table.enum('return_method', ['PICKUP', 'DROP_OFF', 'SHIPPING_LABEL']).defaultTo('SHIPPING_LABEL');
        table.string('tracking_number', 64);
        table.string('carrier', 64);
        table.datetime('received_at');
        table.datetime('inspected_at');
        table.enum('inspection_result', ['PASSED', 'FAILED', 'PARTIAL']);
        table.text('inspection_note');
        table.integer('restock_quantity').defaultTo(0);
        table.integer('disposal_quantity').defaultTo(0);
        table.string('trace_id', 64);
        table.timestamps(true, true);

        table.index(['tenant_id', 'status'], 'idx_return_tenant_status');
        table.index(['tenant_id', 'order_id'], 'idx_return_tenant_order');
      });
      logger.info(`[AfterSales] Table ${this.RETURN_TABLE} created`);
    }
  }

  static async createRequest(
    context: AfterSalesContext,
    requestData: {
      orderId: string;
      type: AfterSalesType;
      reason: string;
      description?: string;
      items: AfterSalesItem[];
      customerId: string;
      customerName: string;
      customerEmail?: string;
    }
  ): Promise<AfterSalesResult> {
    const { tenantId, traceId } = context;
    logger.info(`[AfterSales] Creating request - orderId: ${requestData.orderId}, type: ${requestData.type}, traceId: ${traceId}`);

    try {
      const order = await db('cf_order_fulfillment')
        .where({ id: requestData.orderId, tenant_id: tenantId })
        .first();

      if (!order) {
        throw new Error(`Order not found: ${requestData.orderId}`);
      }

      const canRequest = this.canRequestAfterSales(order.status, order.created_at);
      if (!canRequest.allowed) {
        throw new Error(canRequest.reason);
      }

      const existingRequest = await db(this.AFTER_SALES_TABLE)
        .where({
          tenant_id: tenantId,
          order_id: requestData.orderId,
          status: ['PENDING', 'APPROVED', 'PROCESSING']
        })
        .whereIn('status', ['PENDING', 'APPROVED', 'PROCESSING'])
        .first();

      if (existingRequest) {
        throw new Error('An active after-sales request already exists for this order');
      }

      const totalAmount = requestData.items.reduce((sum, item) => sum + item.totalPrice, 0);
      const afterSalesId = this.generateId();

      const afterSales: AfterSalesRequest = {
        id: afterSalesId,
        tenantId,
        orderId: requestData.orderId,
        type: requestData.type,
        status: 'PENDING',
        reason: requestData.reason,
        description: requestData.description,
        items: requestData.items,
        customerId: requestData.customerId,
        customerName: requestData.customerName,
        customerEmail: requestData.customerEmail,
        totalAmount,
        traceId,
        createdAt: new Date(),
        updatedAt: new Date()
      };

      await db(this.AFTER_SALES_TABLE).insert({
        id: afterSales.id,
        tenant_id: afterSales.tenantId,
        order_id: afterSales.orderId,
        type: afterSales.type,
        status: afterSales.status,
        reason: afterSales.reason,
        description: afterSales.description,
        items: JSON.stringify(afterSales.items),
        customer_id: afterSales.customerId,
        customer_name: afterSales.customerName,
        customer_email: afterSales.customerEmail,
        total_amount: afterSales.totalAmount,
        trace_id: afterSales.traceId,
        created_at: afterSales.createdAt,
        updated_at: afterSales.updatedAt
      });

      DomainEventBus.publish('after_sales.created', {
        afterSalesId,
        tenantId,
        orderId: requestData.orderId,
        type: requestData.type,
        timestamp: new Date()
      });

      logger.info(`[AfterSales] Request created: ${afterSalesId}`);

      return {
        success: true,
        afterSalesId,
        status: 'PENDING',
        message: 'After-sales request created successfully'
      };
    } catch (error: any) {
      logger.error(`[AfterSales] Create request failed: ${error.message}`);
      throw error;
    }
  }

  private static canRequestAfterSales(orderStatus: string, orderCreatedAt: Date): { allowed: boolean; reason?: string } {
    if (orderStatus === 'CANCELLED') {
      return { allowed: false, reason: 'Cannot request after-sales for cancelled order' };
    }

    if (orderStatus === 'PULLED' || orderStatus === 'PENDING_REVIEW') {
      return { allowed: false, reason: 'Order must be confirmed before requesting after-sales' };
    }

    const daysSinceOrder = Math.floor((Date.now() - new Date(orderCreatedAt).getTime()) / (1000 * 60 * 60 * 24));
    if (daysSinceOrder > RETURN_DEADLINE_DAYS) {
      return { allowed: false, reason: `Return period expired (${RETURN_DEADLINE_DAYS} days)` };
    }

    return { allowed: true };
  }

  static async approveRequest(
    context: AfterSalesContext,
    afterSalesId: string,
    approvalData: {
      approved: boolean;
      approvedBy: string;
      rejectedReason?: string;
      refundAmount?: number;
    }
  ): Promise<AfterSalesResult> {
    const { tenantId, traceId } = context;
    logger.info(`[AfterSales] ${approvalData.approved ? 'Approving' : 'Rejecting'} request: ${afterSalesId}`);

    try {
      const request = await this.getRequestById(tenantId, afterSalesId);
      if (!request) {
        throw new Error(`After-sales request not found: ${afterSalesId}`);
      }

      if (request.status !== 'PENDING') {
        throw new Error(`Invalid status for approval: ${request.status}`);
      }

      const newStatus = approvalData.approved ? 'APPROVED' : 'REJECTED';

      await db(this.AFTER_SALES_TABLE)
        .where({ id: afterSalesId, tenant_id: tenantId })
        .update({
          status: newStatus,
          approved_by: approvalData.approvedBy,
          approved_at: approvalData.approved ? new Date() : null,
          rejected_reason: approvalData.rejectedReason,
          refund_amount: approvalData.refundAmount,
          updated_at: new Date()
        });

      if (approvalData.approved) {
        await this.processApprovedRequest(context, request, approvalData.refundAmount);
      }

      DomainEventBus.publish('after_sales.status_changed', {
        afterSalesId,
        tenantId,
        status: newStatus,
        approved: approvalData.approved,
        timestamp: new Date()
      });

      return {
        success: true,
        afterSalesId,
        status: newStatus,
        message: approvalData.approved ? 'Request approved' : 'Request rejected'
      };
    } catch (error: any) {
      logger.error(`[AfterSales] Approval failed: ${error.message}`);
      throw error;
    }
  }

  private static async processApprovedRequest(
    context: AfterSalesContext,
    request: AfterSalesRequest,
    refundAmount?: number
  ): Promise<void> {
    const { tenantId, traceId } = context;

    if (request.type === 'REFUND' || request.type === 'CANCEL') {
      await this.createRefundRecord(tenantId, {
        orderId: request.orderId,
        afterSalesId: request.id,
        amount: refundAmount || request.totalAmount,
        reason: request.reason,
        traceId
      });
    }

    if (request.type === 'RETURN' || request.type === 'EXCHANGE') {
      await this.createReturnRecord(tenantId, {
        orderId: request.orderId,
        afterSalesId: request.id,
        traceId
      });
    }

    await db(this.AFTER_SALES_TABLE)
      .where({ id: request.id, tenant_id: tenantId })
      .update({
        status: 'PROCESSING',
        processed_at: new Date(),
        updated_at: new Date()
      });
  }

  static async processRefund(
    context: AfterSalesContext,
    refundId: string,
    processData: {
      transactionId?: string;
      refundMethod?: string;
    }
  ): Promise<AfterSalesResult> {
    const { tenantId, traceId } = context;
    logger.info(`[AfterSales] Processing refund: ${refundId}`);

    try {
      const refund = await db(this.REFUND_TABLE)
        .where({ id: refundId, tenant_id: tenantId })
        .first();

      if (!refund) {
        throw new Error(`Refund not found: ${refundId}`);
      }

      if (refund.status !== 'APPROVED' && refund.status !== 'PENDING') {
        throw new Error(`Invalid refund status: ${refund.status}`);
      }

      await db(this.REFUND_TABLE)
        .where({ id: refundId, tenant_id: tenantId })
        .update({
          status: 'PROCESSING',
          transaction_id: processData.transactionId,
          refund_method: processData.refundMethod,
          processed_at: new Date(),
          updated_at: new Date()
        });

      const success = await this.executeRefund(refund);

      if (success) {
        await db(this.REFUND_TABLE)
          .where({ id: refundId, tenant_id: tenantId })
          .update({
            status: 'COMPLETED',
            completed_at: new Date(),
            updated_at: new Date()
          });

        if (refund.after_sales_id) {
          await this.checkAndCompleteAfterSales(tenantId, refund.after_sales_id);
        }

        DomainEventBus.publish('refund.completed', {
          refundId,
          tenantId,
          orderId: refund.order_id,
          amount: Number(refund.amount),
          timestamp: new Date()
        });
      } else {
        await db(this.REFUND_TABLE)
          .where({ id: refundId, tenant_id: tenantId })
          .update({
            status: 'FAILED',
            failed_reason: 'Refund processing failed',
            updated_at: new Date()
          });
      }

      return {
        success,
        afterSalesId: refund.after_sales_id,
        status: success ? 'COMPLETED' : 'PROCESSING',
        message: success ? 'Refund processed successfully' : 'Refund processing failed'
      };
    } catch (error: any) {
      logger.error(`[AfterSales] Process refund failed: ${error.message}`);
      throw error;
    }
  }

  private static async executeRefund(refund: any): Promise<boolean> {
    logger.info(`[AfterSales] Executing refund for order: ${refund.order_id}, amount: ${refund.amount}`);
    return true;
  }

  static async processReturn(
    context: AfterSalesContext,
    returnId: string,
    action: 'receive' | 'inspect' | 'complete',
    actionData: {
      trackingNumber?: string;
      carrier?: string;
      inspectionResult?: 'PASSED' | 'FAILED' | 'PARTIAL';
      inspectionNote?: string;
      restockQuantity?: number;
      disposalQuantity?: number;
    }
  ): Promise<AfterSalesResult> {
    const { tenantId, traceId } = context;
    logger.info(`[AfterSales] Processing return: ${returnId}, action: ${action}`);

    try {
      const returnRecord = await db(this.RETURN_TABLE)
        .where({ id: returnId, tenant_id: tenantId })
        .first();

      if (!returnRecord) {
        throw new Error(`Return not found: ${returnId}`);
      }

      const updateData: Record<string, any> = { updated_at: new Date() };

      switch (action) {
        case 'receive':
          updateData.status = 'RECEIVED';
          updateData.tracking_number = actionData.trackingNumber;
          updateData.carrier = actionData.carrier;
          updateData.received_at = new Date();
          break;

        case 'inspect':
          updateData.status = 'INSPECTING';
          updateData.inspected_at = new Date();
          break;

        case 'complete':
          updateData.status = 'COMPLETED';
          updateData.inspection_result = actionData.inspectionResult;
          updateData.inspection_note = actionData.inspectionNote;
          updateData.restock_quantity = actionData.restockQuantity || 0;
          updateData.disposal_quantity = actionData.disposalQuantity || 0;

          if (actionData.restockQuantity && actionData.restockQuantity > 0) {
            const afterSales = await db(this.AFTER_SALES_TABLE)
              .where({ id: returnRecord.after_sales_id, tenant_id: tenantId })
              .first();

            if (afterSales) {
              const items = typeof afterSales.items === 'string' ? JSON.parse(afterSales.items) : afterSales.items;
              for (const item of items) {
                await InventoryService.adjustStock(
                  tenantId,
                  item.skuId,
                  actionData.restockQuantity,
                  undefined
                );
              }
            }
          }

          if (returnRecord.after_sales_id) {
            await this.checkAndCompleteAfterSales(tenantId, returnRecord.after_sales_id);
          }
          break;
      }

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

      DomainEventBus.publish('return.status_changed', {
        returnId,
        tenantId,
        status: updateData.status,
        action,
        timestamp: new Date()
      });

      return {
        success: true,
        afterSalesId: returnRecord.after_sales_id,
        status: updateData.status,
        message: `Return ${action} processed successfully`
      };
    } catch (error: any) {
      logger.error(`[AfterSales] Process return failed: ${error.message}`);
      throw error;
    }
  }

  private static async checkAndCompleteAfterSales(tenantId: string, afterSalesId: string): Promise<void> {
    const afterSales = await db(this.AFTER_SALES_TABLE)
      .where({ id: afterSalesId, tenant_id: tenantId })
      .first();

    if (!afterSales) return;

    let allComplete = false;

    if (afterSales.type === 'REFUND' || afterSales.type === 'CANCEL') {
      const refund = await db(this.REFUND_TABLE)
        .where({ after_sales_id: afterSalesId, tenant_id: tenantId })
        .first();
      allComplete = refund?.status === 'COMPLETED';
    } else if (afterSales.type === 'RETURN' || afterSales.type === 'EXCHANGE') {
      const returnRecord = await db(this.RETURN_TABLE)
        .where({ after_sales_id: afterSalesId, tenant_id: tenantId })
        .first();
      allComplete = returnRecord?.status === 'COMPLETED';
    }

    if (allComplete) {
      await db(this.AFTER_SALES_TABLE)
        .where({ id: afterSalesId, tenant_id: tenantId })
        .update({
          status: 'COMPLETED',
          completed_at: new Date(),
          updated_at: new Date()
        });

      DomainEventBus.publish('after_sales.completed', {
        afterSalesId,
        tenantId,
        timestamp: new Date()
      });
    }
  }

  private static async createRefundRecord(
    tenantId: string,
    data: {
      orderId: string;
      afterSalesId?: string;
      amount: number;
      reason: string;
      traceId: string;
    }
  ): Promise<string> {
    const refundId = this.generateRefundId();

    await db(this.REFUND_TABLE).insert({
      id: refundId,
      tenant_id: tenantId,
      order_id: data.orderId,
      after_sales_id: data.afterSalesId,
      amount: data.amount,
      currency: 'USD',
      status: 'PENDING',
      reason: data.reason,
      trace_id: data.traceId,
      created_at: new Date(),
      updated_at: new Date()
    });

    return refundId;
  }

  private static async createReturnRecord(
    tenantId: string,
    data: {
      orderId: string;
      afterSalesId?: string;
      traceId: string;
    }
  ): Promise<string> {
    const returnId = this.generateReturnId();

    await db(this.RETURN_TABLE).insert({
      id: returnId,
      tenant_id: tenantId,
      order_id: data.orderId,
      after_sales_id: data.afterSalesId,
      status: 'PENDING',
      return_method: 'SHIPPING_LABEL',
      trace_id: data.traceId,
      created_at: new Date(),
      updated_at: new Date()
    });

    return returnId;
  }

  static async getRequestById(tenantId: string, afterSalesId: string): Promise<AfterSalesRequest | null> {
    const request = await db(this.AFTER_SALES_TABLE)
      .where({ id: afterSalesId, tenant_id: tenantId })
      .first();

    if (!request) return null;

    return this.mapToRequest(request);
  }

  static async getRequests(
    tenantId: string,
    params: {
      status?: AfterSalesStatus;
      type?: AfterSalesType;
      orderId?: string;
      page?: number;
      pageSize?: number;
    }
  ): Promise<{ requests: AfterSalesRequest[]; total: number }> {
    const { status, type, orderId, page = 1, pageSize = 20 } = params;
    const offset = (page - 1) * pageSize;

    let query = db(this.AFTER_SALES_TABLE).where({ tenant_id: tenantId });

    if (status) query = query.where({ status });
    if (type) query = query.where({ type });
    if (orderId) query = query.where({ order_id: orderId });

    const total = await query.clone().count('id as count').first();

    const requests = await query
      .offset(offset)
      .limit(pageSize)
      .orderBy('created_at', 'desc');

    return {
      requests: requests.map(r => this.mapToRequest(r)),
      total: Number(total?.count || 0)
    };
  }

  static async getRefundById(tenantId: string, refundId: string): Promise<RefundRecord | null> {
    const refund = await db(this.REFUND_TABLE)
      .where({ id: refundId, tenant_id: tenantId })
      .first();

    if (!refund) return null;

    return this.mapToRefund(refund);
  }

  static async getReturnById(tenantId: string, returnId: string): Promise<ReturnRecord | null> {
    const returnRecord = await db(this.RETURN_TABLE)
      .where({ id: returnId, tenant_id: tenantId })
      .first();

    if (!returnRecord) return null;

    return this.mapToReturn(returnRecord);
  }

  static async closeRequest(
    context: AfterSalesContext,
    afterSalesId: string,
    reason: string
  ): Promise<AfterSalesResult> {
    const { tenantId, traceId } = context;
    logger.info(`[AfterSales] Closing request: ${afterSalesId}`);

    try {
      const request = await this.getRequestById(tenantId, afterSalesId);
      if (!request) {
        throw new Error(`After-sales request not found: ${afterSalesId}`);
      }

      if (request.status === 'COMPLETED') {
        throw new Error('Cannot close completed request');
      }

      await db(this.AFTER_SALES_TABLE)
        .where({ id: afterSalesId, tenant_id: tenantId })
        .update({
          status: 'CLOSED',
          updated_at: new Date()
        });

      return {
        success: true,
        afterSalesId,
        status: 'CLOSED',
        message: `Request closed: ${reason}`
      };
    } catch (error: any) {
      logger.error(`[AfterSales] Close request failed: ${error.message}`);
      throw error;
    }
  }

  private static mapToRequest(row: any): AfterSalesRequest {
    return {
      id: row.id,
      tenantId: row.tenant_id,
      orderId: row.order_id,
      type: row.type,
      status: row.status,
      reason: row.reason,
      description: row.description,
      items: typeof row.items === 'string' ? JSON.parse(row.items) : row.items,
      customerId: row.customer_id,
      customerName: row.customer_name,
      customerEmail: row.customer_email,
      totalAmount: Number(row.total_amount),
      refundAmount: row.refund_amount ? Number(row.refund_amount) : undefined,
      approvedBy: row.approved_by,
      approvedAt: row.approved_at,
      rejectedReason: row.rejected_reason,
      processedAt: row.processed_at,
      completedAt: row.completed_at,
      traceId: row.trace_id,
      createdAt: row.created_at,
      updatedAt: row.updated_at
    };
  }

  private static mapToRefund(row: any): RefundRecord {
    return {
      id: row.id,
      tenantId: row.tenant_id,
      orderId: row.order_id,
      afterSalesId: row.after_sales_id,
      amount: Number(row.amount),
      currency: row.currency,
      status: row.status,
      reason: row.reason,
      refundMethod: row.refund_method,
      transactionId: row.transaction_id,
      processedAt: row.processed_at,
      completedAt: row.completed_at,
      failedReason: row.failed_reason,
      traceId: row.trace_id,
      createdAt: row.created_at,
      updatedAt: row.updated_at
    };
  }

  private static mapToReturn(row: any): ReturnRecord {
    return {
      id: row.id,
      tenantId: row.tenant_id,
      orderId: row.order_id,
      afterSalesId: row.after_sales_id,
      status: row.status,
      returnMethod: row.return_method,
      trackingNumber: row.tracking_number,
      carrier: row.carrier,
      receivedAt: row.received_at,
      inspectedAt: row.inspected_at,
      inspectionResult: row.inspection_result,
      inspectionNote: row.inspection_note,
      restockQuantity: row.restock_quantity,
      disposalQuantity: row.disposal_quantity,
      traceId: row.trace_id,
      createdAt: row.created_at,
      updatedAt: row.updated_at
    };
  }

  private static generateId(): string {
    return `AS-${Date.now()}-${Math.random().toString(36).substr(2, 6).toUpperCase()}`;
  }

  private static generateRefundId(): string {
    return `REF-${Date.now()}-${Math.random().toString(36).substr(2, 6).toUpperCase()}`;
  }

  private static generateReturnId(): string {
    return `RET-${Date.now()}-${Math.random().toString(36).substr(2, 6).toUpperCase()}`;
  }
}
