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

export interface ReturnRequest {
  orderId: string;
  reason: string;
  items: ReturnItem[];
  tenantId: string;
  shopId: string;
  taskId: string;
  traceId: string;
  businessType: 'TOC' | 'TOB';
}

export interface ReturnItem {
  productId: string;
  skuId: string;
  quantity: number;
  reason?: string;
}

export interface ReturnRecord {
  id: string;
  orderId: string;
  status: ReturnStatus;
  reason: string;
  items: ReturnItem[];
  totalRefundAmount: number;
  tenantId: string;
  shopId: string;
  taskId: string;
  traceId: string;
  businessType: 'TOC' | 'TOB';
  createdAt: Date;
  updatedAt: Date;
}

export type ReturnStatus = 
  | 'PENDING'
  | 'APPROVED'
  | 'REJECTED'
  | 'RETURNED'
  | 'REFUNDED'
  | 'CLOSED';

export interface RefundRequest {
  returnId: string;
  approvalResult: 'APPROVED' | 'REJECTED';
  approvedAmount?: number;
  reason?: string;
  tenantId: string;
  shopId: string;
  taskId: string;
  traceId: string;
  businessType: 'TOC' | 'TOB';
}

export interface RefundRecord {
  id: string;
  returnId: string;
  orderId: string;
  amount: number;
  status: RefundStatus;
  method: string;
  tenantId: string;
  shopId: string;
  taskId: string;
  traceId: string;
  businessType: 'TOC' | 'TOB';
  createdAt: Date;
  updatedAt: Date;
}

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

export interface ServiceTicket {
  id: string;
  returnId: string;
  type: TicketType;
  priority: TicketPriority;
  status: TicketStatus;
  subject: string;
  description: string;
  messages: TicketMessage[];
  tenantId: string;
  shopId: string;
  taskId: string;
  traceId: string;
  businessType: 'TOC' | 'TOB';
  createdAt: Date;
  updatedAt: Date;
}

export type TicketType = 
  | 'RETURN'
  | 'REFUND'
  | 'EXCHANGE'
  | 'COMPLAINT'
  | 'INQUIRY';

export type TicketPriority = 
  | 'LOW'
  | 'MEDIUM'
  | 'HIGH'
  | 'URGENT';

export type TicketStatus = 
  | 'OPEN'
  | 'IN_PROGRESS'
  | 'WAITING_CUSTOMER'
  | 'WAITING_INTERNAL'
  | 'RESOLVED'
  | 'CLOSED';

export interface TicketMessage {
  id: string;
  sender: 'CUSTOMER' | 'AGENT' | 'SYSTEM';
  content: string;
  attachments?: string[];
  createdAt: Date;
}

export class AfterSalesService {
  static async createReturnRequest(input: ReturnRequest): Promise<ReturnRecord> {
    const { orderId, reason, items, tenantId, shopId, taskId, traceId, businessType } = input;

    logger.info('[AfterSalesService] Creating return request', {
      orderId,
      tenantId,
      shopId,
      taskId,
      traceId,
      businessType,
      itemCount: items.length,
    });

    try {
      const order = await this.getOrderById(orderId, tenantId, traceId);
      if (!order) {
        throw new Error(`Order not found: ${orderId}`);
      }

      if (order.status !== 'DELIVERED' && order.status !== 'COMPLETED') {
        throw new Error(`Order status ${order.status} does not allow return`);
      }

      const returnDaysLimit = 30;
      const deliveredAt = order.deliveredAt || order.updatedAt;
      const daysSinceDelivery = Math.floor(
        (Date.now() - deliveredAt.getTime()) / (1000 * 60 * 60 * 24)
      );

      if (daysSinceDelivery > returnDaysLimit) {
        throw new Error(`Return period expired (${daysSinceDelivery} days)`);
      }

      const returnId = `RET-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
      
      const totalRefundAmount = await this.calculateRefundAmount(
        order,
        items,
        tenantId,
        traceId
      );

      const returnRecord: ReturnRecord = {
        id: returnId,
        orderId,
        status: 'PENDING',
        reason,
        items,
        totalRefundAmount,
        tenantId,
        shopId,
        taskId,
        traceId,
        businessType,
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      await db('cf_return_requests').insert({
        id: returnRecord.id,
        order_id: returnRecord.orderId,
        status: returnRecord.status,
        reason: returnRecord.reason,
        items: JSON.stringify(returnRecord.items),
        total_refund_amount: returnRecord.totalRefundAmount,
        tenant_id: returnRecord.tenantId,
        shop_id: returnRecord.shopId,
        task_id: returnRecord.taskId,
        trace_id: returnRecord.traceId,
        business_type: returnRecord.businessType,
        created_at: returnRecord.createdAt,
        updated_at: returnRecord.updatedAt,
      });

      await this.createServiceTicket({
        returnId,
        type: 'RETURN',
        priority: this.determinePriority(reason),
        subject: `Return Request - Order ${orderId}`,
        description: reason,
        tenantId,
        shopId,
        taskId,
        traceId,
        businessType,
      });

      logger.info('[AfterSalesService] Return request created', {
        returnId,
        orderId,
        tenantId,
        traceId,
        status: returnRecord.status,
      });

      return returnRecord;
    } catch (error: any) {
      logger.error('[AfterSalesService] Failed to create return request', {
        orderId,
        tenantId,
        traceId,
        error: error.message,
      });
      throw error;
    }
  }

  static async processRefund(input: RefundRequest): Promise<RefundRecord> {
    const { returnId, approvalResult, approvedAmount, reason, tenantId, shopId, taskId, traceId, businessType } = input;

    logger.info('[AfterSalesService] Processing refund', {
      returnId,
      approvalResult,
      tenantId,
      shopId,
      taskId,
      traceId,
      businessType,
    });

    try {
      const returnRecord = await this.getReturnById(returnId, tenantId, traceId);
      if (!returnRecord) {
        throw new Error(`Return request not found: ${returnId}`);
      }

      if (returnRecord.status !== 'PENDING' && returnRecord.status !== 'APPROVED') {
        throw new Error(`Return status ${returnRecord.status} cannot be refunded`);
      }

      const refundId = `REF-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
      const refundAmount = approvedAmount || returnRecord.totalRefundAmount;

      let refundStatus: RefundStatus;
      if (approvalResult === 'REJECTED') {
        refundStatus = 'CANCELLED';
      } else {
        refundStatus = 'PENDING_REVIEW';
      }

      const refundRecord: RefundRecord = {
        id: refundId,
        returnId,
        orderId: returnRecord.orderId,
        amount: refundAmount,
        status: refundStatus,
        method: 'ORIGINAL_PAYMENT',
        tenantId,
        shopId,
        taskId,
        traceId,
        businessType,
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      await db('cf_refunds').insert({
        id: refundRecord.id,
        return_id: refundRecord.returnId,
        order_id: refundRecord.orderId,
        amount: refundRecord.amount,
        status: refundRecord.status,
        method: refundRecord.method,
        tenant_id: refundRecord.tenantId,
        shop_id: refundRecord.shopId,
        task_id: refundRecord.taskId,
        trace_id: refundRecord.traceId,
        business_type: refundRecord.businessType,
        created_at: refundRecord.createdAt,
        updated_at: refundRecord.updatedAt,
      });

      if (approvalResult === 'APPROVED') {
        await db('cf_return_requests')
          .where({ id: returnId, tenant_id: tenantId })
          .update({ status: 'APPROVED', updated_at: new Date() });

        await this.executeRefundWorkflow(refundRecord, tenantId, traceId);
      } else {
        await db('cf_return_requests')
          .where({ id: returnId, tenant_id: tenantId })
          .update({ status: 'REJECTED', updated_at: new Date() });
      }

      logger.info('[AfterSalesService] Refund processed', {
        refundId,
        returnId,
        status: refundRecord.status,
        tenantId,
        traceId,
      });

      return refundRecord;
    } catch (error: any) {
      logger.error('[AfterSalesService] Failed to process refund', {
        returnId,
        tenantId,
        traceId,
        error: error.message,
      });
      throw error;
    }
  }

  static async createServiceTicket(input: {
    returnId: string;
    type: TicketType;
    priority: TicketPriority;
    subject: string;
    description: string;
    tenantId: string;
    shopId: string;
    taskId: string;
    traceId: string;
    businessType: 'TOC' | 'TOB';
  }): Promise<ServiceTicket> {
    const { returnId, type, priority, subject, description, tenantId, shopId, taskId, traceId, businessType } = input;

    logger.info('[AfterSalesService] Creating service ticket', {
      returnId,
      type,
      priority,
      tenantId,
      shopId,
      taskId,
      traceId,
      businessType,
    });

    try {
      const ticketId = `TKT-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

      const initialMessage: TicketMessage = {
        id: `MSG-${Date.now()}`,
        sender: 'SYSTEM',
        content: `Ticket created: ${subject}`,
        createdAt: new Date(),
      };

      const ticket: ServiceTicket = {
        id: ticketId,
        returnId,
        type,
        priority,
        status: 'OPEN',
        subject,
        description,
        messages: [initialMessage],
        tenantId,
        shopId,
        taskId,
        traceId,
        businessType,
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      await db('cf_service_tickets').insert({
        id: ticket.id,
        return_id: ticket.returnId,
        type: ticket.type,
        priority: ticket.priority,
        status: ticket.status,
        subject: ticket.subject,
        description: ticket.description,
        messages: JSON.stringify(ticket.messages),
        tenant_id: ticket.tenantId,
        shop_id: ticket.shopId,
        task_id: ticket.taskId,
        trace_id: ticket.traceId,
        business_type: ticket.businessType,
        created_at: ticket.createdAt,
        updated_at: ticket.updatedAt,
      });

      logger.info('[AfterSalesService] Service ticket created', {
        ticketId,
        returnId,
        type,
        priority,
        tenantId,
        traceId,
      });

      return ticket;
    } catch (error: any) {
      logger.error('[AfterSalesService] Failed to create service ticket', {
        returnId,
        tenantId,
        traceId,
        error: error.message,
      });
      throw error;
    }
  }

  static async addTicketMessage(
    ticketId: string,
    sender: 'CUSTOMER' | 'AGENT' | 'SYSTEM',
    content: string,
    options: {
      tenantId: string;
      traceId: string;
      attachments?: string[];
    }
  ): Promise<ServiceTicket> {
    const { tenantId, traceId, attachments } = options;

    logger.info('[AfterSalesService] Adding ticket message', {
      ticketId,
      sender,
      tenantId,
      traceId,
    });

    try {
      const ticket = await db('cf_service_tickets')
        .where({ id: ticketId, tenant_id: tenantId })
        .first();

      if (!ticket) {
        throw new Error(`Ticket not found: ${ticketId}`);
      }

      const messages: TicketMessage[] = JSON.parse(ticket.messages || '[]');
      const newMessage: TicketMessage = {
        id: `MSG-${Date.now()}`,
        sender,
        content,
        attachments,
        createdAt: new Date(),
      };

      messages.push(newMessage);

      await db('cf_service_tickets')
        .where({ id: ticketId, tenant_id: tenantId })
        .update({
          messages: JSON.stringify(messages),
          status: sender === 'CUSTOMER' ? 'IN_PROGRESS' : 'WAITING_CUSTOMER',
          updated_at: new Date(),
        });

      logger.info('[AfterSalesService] Ticket message added', {
        ticketId,
        sender,
        tenantId,
        traceId,
      });

      return {
        ...ticket,
        messages,
      } as ServiceTicket;
    } catch (error: any) {
      logger.error('[AfterSalesService] Failed to add ticket message', {
        ticketId,
        tenantId,
        traceId,
        error: error.message,
      });
      throw error;
    }
  }

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

    if (!record) return null;

    return {
      id: record.id,
      orderId: record.order_id,
      status: record.status,
      reason: record.reason,
      items: JSON.parse(record.items || '[]'),
      totalRefundAmount: Number(record.total_refund_amount),
      tenantId: record.tenant_id,
      shopId: record.shop_id,
      taskId: record.task_id,
      traceId: record.trace_id,
      businessType: record.business_type,
      createdAt: record.created_at,
      updatedAt: record.updated_at,
    };
  }

  private static async getOrderById(orderId: string, tenantId: string, traceId: string): Promise<any> {
    const order = await db('cf_orders')
      .where({ id: orderId, tenant_id: tenantId })
      .first();

    return order;
  }

  private static async calculateRefundAmount(
    order: any,
    items: ReturnItem[],
    tenantId: string,
    traceId: string
  ): Promise<number> {
    const orderItems = JSON.parse(order.items || '[]');
    let totalAmount = 0;

    for (const returnItem of items) {
      const orderItem = orderItems.find((oi: any) => 
        oi.productId === returnItem.productId && oi.skuId === returnItem.skuId
      );
      
      if (orderItem) {
        totalAmount += orderItem.unitPrice * returnItem.quantity;
      }
    }

    return Number(totalAmount.toFixed(2));
  }

  private static determinePriority(reason: string): TicketPriority {
    const highPriorityKeywords = ['损坏', '缺失', '错误', 'damaged', 'missing', 'wrong', 'defective'];
    const urgentKeywords = ['欺诈', '投诉', 'fraud', 'complaint', 'legal'];

    const lowerReason = reason.toLowerCase();

    if (urgentKeywords.some(kw => lowerReason.includes(kw))) {
      return 'URGENT';
    }
    if (highPriorityKeywords.some(kw => lowerReason.includes(kw))) {
      return 'HIGH';
    }
    return 'MEDIUM';
  }

  private static async executeRefundWorkflow(
    refund: RefundRecord,
    tenantId: string,
    traceId: string
  ): Promise<void> {
    logger.info('[AfterSalesService] Executing refund workflow', {
      refundId: refund.id,
      tenantId,
      traceId,
    });

    await db('cf_refunds')
      .where({ id: refund.id, tenant_id: tenantId })
      .update({ status: 'PROCESSING', updated_at: new Date() });

    await new Promise(resolve => setTimeout(resolve, 100));

    await db('cf_refunds')
      .where({ id: refund.id, tenant_id: tenantId })
      .update({ status: 'COMPLETED', updated_at: new Date() });

    await db('cf_return_requests')
      .where({ id: refund.returnId, tenant_id: tenantId })
      .update({ status: 'REFUNDED', updated_at: new Date() });

    logger.info('[AfterSalesService] Refund workflow completed', {
      refundId: refund.id,
      tenantId,
      traceId,
    });
  }

  static async initializeTables(): Promise<void> {
    logger.info('[AfterSalesService] Initializing after-sales tables');

    try {
      if (!(await db.schema.hasTable('cf_return_requests'))) {
        await db.schema.createTable('cf_return_requests', table => {
          table.string('id').primary();
          table.string('order_id').notNullable();
          table.enum('status', ['PENDING', 'APPROVED', 'REJECTED', 'RETURNED', 'REFUNDED', 'CLOSED']).defaultTo('PENDING');
          table.text('reason');
          table.json('items');
          table.decimal('total_refund_amount', 12, 2).defaultTo(0);
          table.string('tenant_id').notNullable();
          table.string('shop_id');
          table.string('task_id');
          table.string('trace_id');
          table.enum('business_type', ['TOC', 'TOB']).defaultTo('TOC');
          table.timestamp('created_at').defaultTo(db.fn.now());
          table.timestamp('updated_at').defaultTo(db.fn.now());
          table.index(['order_id', 'tenant_id']);
          table.index(['status', 'tenant_id']);
        });
        logger.info('[AfterSalesService] Table cf_return_requests created');
      }

      if (!(await db.schema.hasTable('cf_refunds'))) {
        await db.schema.createTable('cf_refunds', table => {
          table.string('id').primary();
          table.string('return_id').notNullable();
          table.string('order_id').notNullable();
          table.decimal('amount', 12, 2).notNullable();
          table.enum('status', ['PENDING_REVIEW', 'APPROVED', 'PROCESSING', 'COMPLETED', 'FAILED', 'CANCELLED']).defaultTo('PENDING_REVIEW');
          table.string('method').defaultTo('ORIGINAL_PAYMENT');
          table.string('tenant_id').notNullable();
          table.string('shop_id');
          table.string('task_id');
          table.string('trace_id');
          table.enum('business_type', ['TOC', 'TOB']).defaultTo('TOC');
          table.timestamp('created_at').defaultTo(db.fn.now());
          table.timestamp('updated_at').defaultTo(db.fn.now());
          table.index(['return_id', 'tenant_id']);
          table.index(['order_id', 'tenant_id']);
          table.index(['status', 'tenant_id']);
        });
        logger.info('[AfterSalesService] Table cf_refunds created');
      }

      if (!(await db.schema.hasTable('cf_service_tickets'))) {
        await db.schema.createTable('cf_service_tickets', table => {
          table.string('id').primary();
          table.string('return_id');
          table.enum('type', ['RETURN', 'REFUND', 'EXCHANGE', 'COMPLAINT', 'INQUIRY']).defaultTo('INQUIRY');
          table.enum('priority', ['LOW', 'MEDIUM', 'HIGH', 'URGENT']).defaultTo('MEDIUM');
          table.enum('status', ['OPEN', 'IN_PROGRESS', 'WAITING_CUSTOMER', 'WAITING_INTERNAL', 'RESOLVED', 'CLOSED']).defaultTo('OPEN');
          table.string('subject');
          table.text('description');
          table.json('messages');
          table.string('tenant_id').notNullable();
          table.string('shop_id');
          table.string('task_id');
          table.string('trace_id');
          table.enum('business_type', ['TOC', 'TOB']).defaultTo('TOC');
          table.timestamp('created_at').defaultTo(db.fn.now());
          table.timestamp('updated_at').defaultTo(db.fn.now());
          table.index(['return_id', 'tenant_id']);
          table.index(['status', 'tenant_id']);
          table.index(['priority', 'tenant_id']);
        });
        logger.info('[AfterSalesService] Table cf_service_tickets created');
      }

      logger.info('[AfterSalesService] After-sales tables initialized successfully');
    } catch (error: any) {
      logger.error(`[AfterSalesService] Failed to initialize after-sales tables - error: ${error.message}`);
      throw error;
    }
  }
}
