/**
 * Withdrawal Management System
 * Handles player withdrawal requests, approvals, and payouts via Square
 */

export type WithdrawalStatus = 'pending' | 'approved' | 'processing' | 'completed' | 'rejected' | 'failed';
export type WithdrawalMethod = 'bank_transfer' | 'square_payout' | 'check';
export type WithdrawalCurrency = 'SC' | 'GC';

export interface WithdrawalRequest {
  id: string;
  playerId: number;
  playerEmail: string;
  playerName: string;
  amount: number;
  currency: WithdrawalCurrency;
  method: WithdrawalMethod;
  status: WithdrawalStatus;
  bankDetails?: {
    accountHolderName: string;
    accountNumber: string;
    routingNumber: string;
    bankName: string;
  };
  squarePayoutId?: string;
  checkNumber?: string;
  requestedAt: Date;
  approvedAt?: Date;
  approvedBy?: number;
  processedAt?: Date;
  completedAt?: Date;
  failureReason?: string;
  notes?: string;
  kycVerified: boolean;
  kycVerifiedAt?: Date;
}

export interface WithdrawalAnalytics {
  totalRequests: number;
  totalAmount: number;
  pendingRequests: number;
  pendingAmount: number;
  approvedRequests: number;
  approvedAmount: number;
  completedRequests: number;
  completedAmount: number;
  rejectedRequests: number;
  rejectedAmount: number;
  averageWithdrawalAmount: number;
  averageProcessingTime: number; // hours
  successRate: number; // percentage
  methodBreakdown: Record<WithdrawalMethod, { count: number; amount: number }>;
}

export interface WithdrawalPolicy {
  minimumAmount: number;
  maximumAmount: number;
  dailyLimit: number;
  monthlyLimit: number;
  requiresKYC: boolean;
  processingTimeHours: number;
  allowedMethods: WithdrawalMethod[];
  feePercentage: number;
  flatFee: number;
}

/**
 * Default withdrawal policy
 * ENFORCED SITEWIDE:
 * - Minimum withdrawal: 100 SC
 * - KYC verification: REQUIRED for all withdrawals
 */
export const DEFAULT_WITHDRAWAL_POLICY: WithdrawalPolicy = {
  minimumAmount: 100, // ENFORCED: Minimum 100 SC
  maximumAmount: 10000,
  dailyLimit: 5000,
  monthlyLimit: 50000,
  requiresKYC: true, // ENFORCED: KYC required for all withdrawals
  processingTimeHours: 24,
  allowedMethods: ['bank_transfer', 'square_payout'],
  feePercentage: 2.5,
  flatFee: 0,
};

/**
 * Create withdrawal request
 */
export function createWithdrawalRequest(
  playerId: number,
  playerEmail: string,
  playerName: string,
  amount: number,
  currency: WithdrawalCurrency,
  method: WithdrawalMethod,
  kycVerified: boolean,
  bankDetails?: {
    accountHolderName: string;
    accountNumber: string;
    routingNumber: string;
    bankName: string;
  }
): WithdrawalRequest {
  return {
    id: `withdrawal_${playerId}_${Date.now()}`,
    playerId,
    playerEmail,
    playerName,
    amount,
    currency,
    method,
    status: 'pending',
    bankDetails,
    requestedAt: new Date(),
    kycVerified,
  };
}

/**
 * Validate withdrawal request against policy
 */
export function validateWithdrawalRequest(
  request: WithdrawalRequest,
  policy: WithdrawalPolicy,
  playerDailyTotal: number,
  playerMonthlyTotal: number
): { valid: boolean; error?: string } {
  // Check KYC requirement
  if (policy.requiresKYC && !request.kycVerified) {
    return { valid: false, error: 'KYC verification required' };
  }

  // Check minimum amount
  if (request.amount < policy.minimumAmount) {
    return {
      valid: false,
      error: `Minimum withdrawal amount is ${policy.minimumAmount} ${request.currency}`,
    };
  }

  // Check maximum amount
  if (request.amount > policy.maximumAmount) {
    return {
      valid: false,
      error: `Maximum withdrawal amount is ${policy.maximumAmount} ${request.currency}`,
    };
  }

  // Check daily limit
  if (playerDailyTotal + request.amount > policy.dailyLimit) {
    return {
      valid: false,
      error: `Daily withdrawal limit of ${policy.dailyLimit} ${request.currency} exceeded`,
    };
  }

  // Check monthly limit
  if (playerMonthlyTotal + request.amount > policy.monthlyLimit) {
    return {
      valid: false,
      error: `Monthly withdrawal limit of ${policy.monthlyLimit} ${request.currency} exceeded`,
    };
  }

  // Check allowed methods
  if (!policy.allowedMethods.includes(request.method)) {
    return { valid: false, error: `Withdrawal method ${request.method} not allowed` };
  }

  // Validate bank details if needed
  if (request.method === 'bank_transfer' && !request.bankDetails) {
    return { valid: false, error: 'Bank details required for bank transfer' };
  }

  return { valid: true };
}

/**
 * Calculate withdrawal fee
 */
export function calculateWithdrawalFee(
  amount: number,
  policy: WithdrawalPolicy
): { fee: number; netAmount: number } {
  const percentageFee = (amount * policy.feePercentage) / 100;
  const totalFee = percentageFee + policy.flatFee;
  const netAmount = amount - totalFee;

  return {
    fee: Math.round(totalFee * 100) / 100,
    netAmount: Math.round(netAmount * 100) / 100,
  };
}

/**
 * Approve withdrawal request
 */
export function approveWithdrawalRequest(
  request: WithdrawalRequest,
  approvedBy: number,
  notes?: string
): void {
  request.status = 'approved';
  request.approvedAt = new Date();
  request.approvedBy = approvedBy;
  request.notes = notes;
}

/**
 * Reject withdrawal request
 */
export function rejectWithdrawalRequest(
  request: WithdrawalRequest,
  reason: string,
  rejectedBy?: number
): void {
  request.status = 'rejected';
  request.failureReason = reason;
  request.approvedBy = rejectedBy;
}

/**
 * Mark withdrawal as processing
 */
export function markWithdrawalProcessing(request: WithdrawalRequest): void {
  request.status = 'processing';
}

/**
 * Mark withdrawal as completed
 */
export function completeWithdrawal(
  request: WithdrawalRequest,
  squarePayoutId?: string,
  checkNumber?: string
): void {
  request.status = 'completed';
  request.completedAt = new Date();
  if (squarePayoutId) request.squarePayoutId = squarePayoutId;
  if (checkNumber) request.checkNumber = checkNumber;
}

/**
 * Mark withdrawal as failed
 */
export function failWithdrawal(request: WithdrawalRequest, reason: string): void {
  request.status = 'failed';
  request.failureReason = reason;
}

/**
 * Retry failed withdrawal
 */
export function retryWithdrawal(request: WithdrawalRequest): void {
  if (request.status === 'failed') {
    request.status = 'pending';
    request.failureReason = undefined;
  }
}

/**
 * Calculate withdrawal analytics
 */
export function calculateWithdrawalAnalytics(
  withdrawals: WithdrawalRequest[]
): WithdrawalAnalytics {
  const totalRequests = withdrawals.length;
  const totalAmount = withdrawals.reduce((sum, w) => sum + w.amount, 0);

  const pending = withdrawals.filter((w) => w.status === 'pending');
  const approved = withdrawals.filter((w) => w.status === 'approved');
  const completed = withdrawals.filter((w) => w.status === 'completed');
  const rejected = withdrawals.filter((w) => w.status === 'rejected');

  const pendingAmount = pending.reduce((sum, w) => sum + w.amount, 0);
  const approvedAmount = approved.reduce((sum, w) => sum + w.amount, 0);
  const completedAmount = completed.reduce((sum, w) => sum + w.amount, 0);
  const rejectedAmount = rejected.reduce((sum, w) => sum + w.amount, 0);

  const averageWithdrawalAmount = totalRequests > 0 ? totalAmount / totalRequests : 0;

  // Calculate average processing time
  const completedWithTime = completed.filter((w) => w.requestedAt && w.completedAt);
  const processingTimes = completedWithTime.map(
    (w) => (w.completedAt!.getTime() - w.requestedAt.getTime()) / (1000 * 60 * 60)
  );
  const averageProcessingTime =
    processingTimes.length > 0
      ? processingTimes.reduce((a, b) => a + b, 0) / processingTimes.length
      : 0;

  const successRate =
    totalRequests > 0 ? ((completed.length + approved.length) / totalRequests) * 100 : 0;

  // Method breakdown
  const methodBreakdown: Record<WithdrawalMethod, { count: number; amount: number }> = {
    bank_transfer: { count: 0, amount: 0 },
    square_payout: { count: 0, amount: 0 },
    check: { count: 0, amount: 0 },
  };

  withdrawals.forEach((w) => {
    methodBreakdown[w.method].count++;
    methodBreakdown[w.method].amount += w.amount;
  });

  return {
    totalRequests,
    totalAmount,
    pendingRequests: pending.length,
    pendingAmount,
    approvedRequests: approved.length,
    approvedAmount,
    completedRequests: completed.length,
    completedAmount,
    rejectedRequests: rejected.length,
    rejectedAmount,
    averageWithdrawalAmount,
    averageProcessingTime,
    successRate,
    methodBreakdown,
  };
}

/**
 * Process Square payout
 */
export async function processSquarePayout(
  request: WithdrawalRequest,
  squareClient: any
): Promise<{ success: boolean; payoutId?: string; error?: string }> {
  try {
    if (!request.bankDetails) {
      return { success: false, error: 'Bank details required' };
    }

    // Create payout via Square API
    const payout = await squareClient.payoutsApi.createPayout({
      payout: {
        amount: Math.round(request.amount * 100), // Convert to cents
        currency: 'USD',
        recipientId: `player_${request.playerId}`, // Would be actual Square customer ID
        description: `Withdrawal for player ${request.playerName}`,
        metadata: {
          playerId: request.playerId,
          withdrawalId: request.id,
        },
      },
    });

    if (payout.result?.payout?.id) {
      return { success: true, payoutId: payout.result.payout.id };
    } else {
      return { success: false, error: 'Failed to create payout' };
    }
  } catch (error) {
    return { success: false, error: (error as Error).message };
  }
}

/**
 * Generate withdrawal report
 */
export interface WithdrawalReport {
  period: 'daily' | 'weekly' | 'monthly';
  startDate: Date;
  endDate: Date;
  analytics: WithdrawalAnalytics;
  topWithdrawals: WithdrawalRequest[];
  recentFailures: WithdrawalRequest[];
  pendingApprovals: WithdrawalRequest[];
}

export function generateWithdrawalReport(
  period: 'daily' | 'weekly' | 'monthly',
  startDate: Date,
  endDate: Date,
  withdrawals: WithdrawalRequest[]
): WithdrawalReport {
  const periodWithdrawals = withdrawals.filter(
    (w) => w.requestedAt >= startDate && w.requestedAt <= endDate
  );

  const analytics = calculateWithdrawalAnalytics(periodWithdrawals);

  const topWithdrawals = [...periodWithdrawals]
    .sort((a, b) => b.amount - a.amount)
    .slice(0, 10);

  const recentFailures = periodWithdrawals
    .filter((w) => w.status === 'failed')
    .sort((a, b) => (b.completedAt?.getTime() || 0) - (a.completedAt?.getTime() || 0))
    .slice(0, 5);

  const pendingApprovals = periodWithdrawals.filter((w) => w.status === 'pending');

  return {
    period,
    startDate,
    endDate,
    analytics,
    topWithdrawals,
    recentFailures,
    pendingApprovals,
  };
}
