import { getDb, creditWallet, writeAuditLog } from './db.ts';
import { eq, and } from 'drizzle-orm';

export interface Referral {
  id: number;
  referrerId: number;
  referredUserId: number;
  referralCode: string;
  status: 'pending' | 'completed' | 'cancelled';
  commissionEarned: number;
  referredUserFirstWager?: number;
  completedAt?: Date;
  createdAt: Date;
}

export interface ReferralStats {
  playerId: number;
  totalReferrals: number;
  completedReferrals: number;
  pendingReferrals: number;
  totalCommissionEarned: number;
  thisMonthCommission: number;
  topReferrer: boolean;
}

/**
 * Referral System Manager
 */
export class ReferralManager {
  private referrals: Map<number, Referral[]> = new Map();
  private referralCodes: Map<string, number> = new Map(); // code -> referrerId

  /**
   * Generate unique referral code
   */
  generateReferralCode(referrerId: number): string {
    const code = `REF${referrerId}${Math.random().toString(36).substring(2, 8).toUpperCase()}`;
    this.referralCodes.set(code, referrerId);
    return code;
  }

  /**
   * Create referral link
   */
  createReferralLink(referrerId: number, baseUrl: string = 'https://coinkrazy.com'): string {
    const code = this.generateReferralCode(referrerId);
    return `${baseUrl}?ref=${code}`;
  }

  /**
   * Register referral (when referred user signs up)
   */
  async registerReferral(referralCode: string, newUserId: number): Promise<{ success: boolean; message: string }> {
    const referrerId = this.referralCodes.get(referralCode);
    if (!referrerId) {
      return { success: false, message: 'Invalid referral code' };
    }

    const referral: Referral = {
      id: Math.random(),
      referrerId,
      referredUserId: newUserId,
      referralCode,
      status: 'pending',
      commissionEarned: 0,
      createdAt: new Date(),
    };

    if (!this.referrals.has(referrerId)) {
      this.referrals.set(referrerId, []);
    }
    this.referrals.get(referrerId)!.push(referral);

    // Log referral registration
    await writeAuditLog({
      actorId: newUserId,
      actorRole: 'user',
      action: 'referral_registered',
      category: 'referral',
      details: {
        referrerId,
        referralCode,
      },
    });

    return { success: true, message: 'Referral registered' };
  }

  /**
   * Complete referral (when referred user makes first wager)
   */
  async completeReferral(
    referralCode: string,
    firstWagerAmount: number
  ): Promise<{ success: boolean; commissionEarned: number }> {
    const referrerId = this.referralCodes.get(referralCode);
    if (!referrerId) {
      return { success: false, commissionEarned: 0 };
    }

    const referrals = this.referrals.get(referrerId) || [];
    const referral = referrals.find((r) => r.referralCode === referralCode && r.status === 'pending');

    if (!referral) {
      return { success: false, commissionEarned: 0 };
    }

    // Calculate commission: 1 SC per referral + 5% of first wager
    const baseCommission = 1;
    const wagerCommission = Math.floor(firstWagerAmount * 0.05);
    const totalCommission = baseCommission + wagerCommission;

    // Credit commission to referrer
    await creditWallet(
      referrerId,
      'SC',
      totalCommission,
      'referral_commission',
      `Referral commission for user ${referral.referredUserId}`,
      String(referrerId)
    );

    // Update referral status
    referral.status = 'completed';
    referral.commissionEarned = totalCommission;
    referral.referredUserFirstWager = firstWagerAmount;
    referral.completedAt = new Date();

    // Log referral completion
    await writeAuditLog({
      actorId: referrerId,
      actorRole: 'user',
      action: 'referral_completed',
      category: 'referral',
      details: {
        referredUserId: referral.referredUserId,
        firstWager: firstWagerAmount,
        commissionEarned: totalCommission,
      },
    });

    return { success: true, commissionEarned: totalCommission };
  }

  /**
   * Get referral stats for player
   */
  async getReferralStats(playerId: number): Promise<ReferralStats> {
    const referrals = this.referrals.get(playerId) || [];

    const totalReferrals = referrals.length;
    const completedReferrals = referrals.filter((r) => r.status === 'completed').length;
    const pendingReferrals = referrals.filter((r) => r.status === 'pending').length;
    const totalCommissionEarned = referrals.reduce((sum, r) => sum + r.commissionEarned, 0);

    // Calculate this month's commission
    const now = new Date();
    const thisMonthCommission = referrals
      .filter((r) => {
        if (!r.completedAt) return false;
        const completedDate = new Date(r.completedAt);
        return completedDate.getMonth() === now.getMonth() && completedDate.getFullYear() === now.getFullYear();
      })
      .reduce((sum, r) => sum + r.commissionEarned, 0);

    return {
      playerId,
      totalReferrals,
      completedReferrals,
      pendingReferrals,
      totalCommissionEarned,
      thisMonthCommission,
      topReferrer: completedReferrals >= 10,
    };
  }

  /**
   * Get referral history
   */
  async getReferralHistory(playerId: number, limit: number = 50): Promise<Referral[]> {
    const referrals = this.referrals.get(playerId) || [];
    return referrals.slice(-limit).reverse();
  }

  /**
   * Get pending referrals
   */
  async getPendingReferrals(playerId: number): Promise<Referral[]> {
    const referrals = this.referrals.get(playerId) || [];
    return referrals.filter((r) => r.status === 'pending');
  }

  /**
   * Get completed referrals
   */
  async getCompletedReferrals(playerId: number): Promise<Referral[]> {
    const referrals = this.referrals.get(playerId) || [];
    return referrals.filter((r) => r.status === 'completed');
  }

  /**
   * Get top referrers
   */
  async getTopReferrers(limit: number = 10): Promise<Array<{ playerId: number; completedReferrals: number; totalCommission: number }>> {
    const topReferrers: Array<{ playerId: number; completedReferrals: number; totalCommission: number }> = [];

    for (const [playerId, referrals] of this.referrals.entries()) {
      const completedReferrals = referrals.filter((r) => r.status === 'completed').length;
      const totalCommission = referrals.reduce((sum, r) => sum + r.commissionEarned, 0);

      if (completedReferrals > 0) {
        topReferrers.push({ playerId, completedReferrals, totalCommission });
      }
    }

    return topReferrers
      .sort((a, b) => b.completedReferrals - a.completedReferrals)
      .slice(0, limit);
  }

  /**
   * Cancel referral
   */
  async cancelReferral(referralCode: string): Promise<{ success: boolean; message: string }> {
    const referrerId = this.referralCodes.get(referralCode);
    if (!referrerId) {
      return { success: false, message: 'Invalid referral code' };
    }

    const referrals = this.referrals.get(referrerId) || [];
    const referral = referrals.find((r) => r.referralCode === referralCode);

    if (!referral) {
      return { success: false, message: 'Referral not found' };
    }

    if (referral.status === 'completed') {
      return { success: false, message: 'Cannot cancel completed referral' };
    }

    referral.status = 'cancelled';

    return { success: true, message: 'Referral cancelled' };
  }

  /**
   * Get referral code for player
   */
  getReferralCode(playerId: number): string | undefined {
    for (const [code, id] of this.referralCodes.entries()) {
      if (id === playerId) {
        return code;
      }
    }
    return undefined;
  }

  /**
   * Get referrer ID from code
   */
  getReferrerId(referralCode: string): number | undefined {
    return this.referralCodes.get(referralCode);
  }
}

export const referralManager = new ReferralManager();

/**
 * Referral tier rewards
 */
export const REFERRAL_TIERS = {
  bronze: {
    minReferrals: 0,
    maxReferrals: 4,
    badge: '🌱',
    title: 'Referral Starter',
  },
  silver: {
    minReferrals: 5,
    maxReferrals: 9,
    badge: '🌿',
    title: 'Referral Grower',
  },
  gold: {
    minReferrals: 10,
    maxReferrals: 24,
    badge: '🌳',
    title: 'Referral Master',
  },
  platinum: {
    minReferrals: 25,
    maxReferrals: 49,
    badge: '🏆',
    title: 'Referral Champion',
  },
  diamond: {
    minReferrals: 50,
    maxReferrals: Infinity,
    badge: '👑',
    title: 'Referral Legend',
  },
};

/**
 * Get referral tier for player
 */
export function getReferralTier(completedReferrals: number): string {
  for (const [tier, config] of Object.entries(REFERRAL_TIERS)) {
    if (completedReferrals >= config.minReferrals && completedReferrals <= config.maxReferrals) {
      return tier;
    }
  }
  return 'bronze';
}
