/**
 * Payment Dispute System
 * Handle payment disputes, chargebacks, and refund requests
 */

export type DisputeStatus = 'open' | 'investigating' | 'resolved' | 'escalated' | 'closed';
export type DisputeReason = 'chargeback' | 'refund_request' | 'unauthorized' | 'duplicate' | 'other';
export type DisputeResolution = 'refunded' | 'denied' | 'partial_refund' | 'pending';

export interface PaymentDispute {
  id: string;
  transactionId: string;
  userId: number;
  reason: DisputeReason;
  status: DisputeStatus;
  amount: number;
  description: string;
  evidence: string[];
  resolution?: DisputeResolution;
  refundAmount?: number;
  createdAt: Date;
  updatedAt: Date;
  resolvedAt?: Date;
  notes: DisputeNote[];
  auditTrail: AuditEntry[];
}

export interface DisputeNote {
  id: string;
  author: string; // admin or user
  content: string;
  createdAt: Date;
  isInternal: boolean;
}

export interface AuditEntry {
  id: string;
  action: string;
  actor: string;
  timestamp: Date;
  changes: Record<string, any>;
}

export interface DisputeStats {
  totalDisputes: number;
  openDisputes: number;
  investigatingDisputes: number;
  resolvedDisputes: number;
  escalatedDisputes: number;
  totalDisputedAmount: number;
  averageResolutionTime: number; // days
  refundRate: number; // percentage
  chargebackRate: number; // percentage
}

/**
 * Create a new dispute
 */
export function createDispute(
  transactionId: string,
  userId: number,
  reason: DisputeReason,
  description: string,
  amount: number
): PaymentDispute {
  return {
    id: `DISPUTE-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
    transactionId,
    userId,
    reason,
    status: 'open',
    amount,
    description,
    evidence: [],
    createdAt: new Date(),
    updatedAt: new Date(),
    notes: [],
    auditTrail: [
      {
        id: `AUDIT-${Date.now()}`,
        action: 'dispute_created',
        actor: `user_${userId}`,
        timestamp: new Date(),
        changes: { reason, amount, description },
      },
    ],
  };
}

/**
 * Add evidence to dispute
 */
export function addEvidence(
  dispute: PaymentDispute,
  evidence: string,
  actor: string
): PaymentDispute {
  return {
    ...dispute,
    evidence: [...dispute.evidence, evidence],
    updatedAt: new Date(),
    auditTrail: [
      ...dispute.auditTrail,
      {
        id: `AUDIT-${Date.now()}`,
        action: 'evidence_added',
        actor,
        timestamp: new Date(),
        changes: { evidence },
      },
    ],
  };
}

/**
 * Add note to dispute
 */
export function addNote(
  dispute: PaymentDispute,
  content: string,
  author: string,
  isInternal: boolean = false
): PaymentDispute {
  const note: DisputeNote = {
    id: `NOTE-${Date.now()}`,
    author,
    content,
    createdAt: new Date(),
    isInternal,
  };

  return {
    ...dispute,
    notes: [...dispute.notes, note],
    updatedAt: new Date(),
    auditTrail: [
      ...dispute.auditTrail,
      {
        id: `AUDIT-${Date.now()}`,
        action: 'note_added',
        actor: author,
        timestamp: new Date(),
        changes: { note: note.id, isInternal },
      },
    ],
  };
}

/**
 * Update dispute status
 */
export function updateDisputeStatus(
  dispute: PaymentDispute,
  newStatus: DisputeStatus,
  actor: string
): PaymentDispute {
  return {
    ...dispute,
    status: newStatus,
    updatedAt: new Date(),
    auditTrail: [
      ...dispute.auditTrail,
      {
        id: `AUDIT-${Date.now()}`,
        action: 'status_updated',
        actor,
        timestamp: new Date(),
        changes: { from: dispute.status, to: newStatus },
      },
    ],
  };
}

/**
 * Resolve dispute
 */
export function resolveDispute(
  dispute: PaymentDispute,
  resolution: DisputeResolution,
  refundAmount: number,
  actor: string,
  notes?: string
): PaymentDispute {
  let updated = {
    ...dispute,
    status: 'resolved' as DisputeStatus,
    resolution,
    refundAmount,
    resolvedAt: new Date(),
    updatedAt: new Date(),
    auditTrail: [
      ...dispute.auditTrail,
      {
        id: `AUDIT-${Date.now()}`,
        action: 'dispute_resolved',
        actor,
        timestamp: new Date(),
        changes: { resolution, refundAmount },
      },
    ],
  };

  if (notes) {
    updated = addNote(updated, notes, actor, true);
  }

  return updated;
}

/**
 * Escalate dispute
 */
export function escalateDispute(
  dispute: PaymentDispute,
  reason: string,
  actor: string
): PaymentDispute {
  return {
    ...dispute,
    status: 'escalated',
    updatedAt: new Date(),
    auditTrail: [
      ...dispute.auditTrail,
      {
        id: `AUDIT-${Date.now()}`,
        action: 'dispute_escalated',
        actor,
        timestamp: new Date(),
        changes: { reason },
      },
    ],
    notes: [
      ...dispute.notes,
      {
        id: `NOTE-${Date.now()}`,
        author: actor,
        content: `Escalated: ${reason}`,
        createdAt: new Date(),
        isInternal: true,
      },
    ],
  };
}

/**
 * Calculate dispute statistics
 */
export function calculateDisputeStats(disputes: PaymentDispute[]): DisputeStats {
  const totalDisputes = disputes.length;
  const openDisputes = disputes.filter(d => d.status === 'open').length;
  const investigatingDisputes = disputes.filter(d => d.status === 'investigating').length;
  const resolvedDisputes = disputes.filter(d => d.status === 'resolved').length;
  const escalatedDisputes = disputes.filter(d => d.status === 'escalated').length;

  const totalDisputedAmount = disputes.reduce((sum, d) => sum + d.amount, 0);

  // Calculate average resolution time
  const resolvedWithTime = disputes
    .filter(d => d.resolvedAt && d.createdAt)
    .map(d => (d.resolvedAt!.getTime() - d.createdAt.getTime()) / (1000 * 60 * 60 * 24));

  const averageResolutionTime =
    resolvedWithTime.length > 0
      ? resolvedWithTime.reduce((a, b) => a + b, 0) / resolvedWithTime.length
      : 0;

  // Calculate refund rate
  const refundedDisputes = disputes.filter(
    d => d.resolution === 'refunded' || d.resolution === 'partial_refund'
  ).length;
  const refundRate = totalDisputes > 0 ? (refundedDisputes / totalDisputes) * 100 : 0;

  // Calculate chargeback rate
  const chargebackDisputes = disputes.filter(d => d.reason === 'chargeback').length;
  const chargebackRate = totalDisputes > 0 ? (chargebackDisputes / totalDisputes) * 100 : 0;

  return {
    totalDisputes,
    openDisputes,
    investigatingDisputes,
    resolvedDisputes,
    escalatedDisputes,
    totalDisputedAmount,
    averageResolutionTime,
    refundRate,
    chargebackRate,
  };
}

/**
 * Get disputes by status
 */
export function getDisputesByStatus(
  disputes: PaymentDispute[],
  status: DisputeStatus
): PaymentDispute[] {
  return disputes.filter(d => d.status === status);
}

/**
 * Get disputes by reason
 */
export function getDisputesByReason(
  disputes: PaymentDispute[],
  reason: DisputeReason
): PaymentDispute[] {
  return disputes.filter(d => d.reason === reason);
}

/**
 * Get disputes by user
 */
export function getDisputesByUser(
  disputes: PaymentDispute[],
  userId: number
): PaymentDispute[] {
  return disputes.filter(d => d.userId === userId);
}

/**
 * Get disputes by transaction
 */
export function getDisputesByTransaction(
  disputes: PaymentDispute[],
  transactionId: string
): PaymentDispute[] {
  return disputes.filter(d => d.transactionId === transactionId);
}

/**
 * Generate dispute report
 */
export function generateDisputeReport(disputes: PaymentDispute[]): string {
  const stats = calculateDisputeStats(disputes);
  const now = new Date();

  return `
PAYMENT DISPUTE REPORT
Generated: ${now.toISOString()}

SUMMARY
-------
Total Disputes: ${stats.totalDisputes}
Open: ${stats.openDisputes}
Investigating: ${stats.investigatingDisputes}
Resolved: ${stats.resolvedDisputes}
Escalated: ${stats.escalatedDisputes}

FINANCIAL IMPACT
----------------
Total Disputed Amount: $${stats.totalDisputedAmount.toFixed(2)}
Average Resolution Time: ${stats.averageResolutionTime.toFixed(1)} days
Refund Rate: ${stats.refundRate.toFixed(1)}%
Chargeback Rate: ${stats.chargebackRate.toFixed(1)}%

BREAKDOWN BY REASON
-------------------
${getDisputesByReason(disputes, 'chargeback').length} Chargebacks
${getDisputesByReason(disputes, 'refund_request').length} Refund Requests
${getDisputesByReason(disputes, 'unauthorized').length} Unauthorized
${getDisputesByReason(disputes, 'duplicate').length} Duplicates
${getDisputesByReason(disputes, 'other').length} Other

BREAKDOWN BY RESOLUTION
-----------------------
${disputes.filter(d => d.resolution === 'refunded').length} Refunded
${disputes.filter(d => d.resolution === 'denied').length} Denied
${disputes.filter(d => d.resolution === 'partial_refund').length} Partial Refunds
${disputes.filter(d => d.resolution === 'pending').length} Pending
  `;
}

/**
 * Export disputes to CSV
 */
export function exportDisputesToCSV(disputes: PaymentDispute[]): string {
  const headers = [
    'Dispute ID',
    'Transaction ID',
    'User ID',
    'Reason',
    'Status',
    'Amount',
    'Resolution',
    'Refund Amount',
    'Created At',
    'Resolved At',
    'Notes Count',
  ];

  const rows = disputes.map(d => [
    d.id,
    d.transactionId,
    d.userId,
    d.reason,
    d.status,
    d.amount,
    d.resolution || 'N/A',
    d.refundAmount || 0,
    d.createdAt.toISOString(),
    d.resolvedAt?.toISOString() || 'N/A',
    d.notes.length,
  ]);

  const csv = [
    headers.join(','),
    ...rows.map(row => row.map(cell => `"${cell}"`).join(',')),
  ].join('\n');

  return csv;
}

/**
 * Validate dispute resolution
 */
export function validateDisputeResolution(
  dispute: PaymentDispute,
  refundAmount: number
): { valid: boolean; error?: string } {
  if (refundAmount < 0) {
    return { valid: false, error: 'Refund amount cannot be negative' };
  }

  if (refundAmount > dispute.amount) {
    return { valid: false, error: 'Refund amount cannot exceed dispute amount' };
  }

  if (dispute.status === 'resolved') {
    return { valid: false, error: 'Dispute is already resolved' };
  }

  if (dispute.status === 'closed') {
    return { valid: false, error: 'Dispute is closed' };
  }

  return { valid: true };
}

/**
 * Get dispute timeline
 */
export function getDisputeTimeline(dispute: PaymentDispute): string {
  let timeline = `Dispute Timeline for ${dispute.id}\n`;
  timeline += `Status: ${dispute.status}\n\n`;

  dispute.auditTrail.forEach(entry => {
    timeline += `[${entry.timestamp.toISOString()}] ${entry.action} by ${entry.actor}\n`;
    if (Object.keys(entry.changes).length > 0) {
      timeline += `  Changes: ${JSON.stringify(entry.changes)}\n`;
    }
  });

  return timeline;
}
