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

export interface PlayerProfile {
  id: number;
  username: string;
  avatar?: string;
  bio?: string;
  level: number;
  totalWagered: number;
  totalWon: number;
  gamesPlayed: number;
  vipTier: string;
  joinedAt: Date;
  lastSeenAt: Date;
}

export interface Friend {
  id: number;
  playerId: number;
  friendId: number;
  status: 'pending' | 'accepted' | 'blocked';
  createdAt: Date;
  acceptedAt?: Date;
}

export interface LeaderboardEntry {
  rank: number;
  playerId: number;
  username: string;
  score: number;
  vipTier: string;
  avatar?: string;
}

/**
 * Social Features Manager
 */
export class SocialManager {
  private friendships: Map<number, Friend[]> = new Map();
  private playerProfiles: Map<number, PlayerProfile> = new Map();
  private leaderboards: Map<string, LeaderboardEntry[]> = new Map();

  /**
   * Initialize player profile
   */
  async initializeProfile(playerId: number, username: string): Promise<PlayerProfile> {
    const profile: PlayerProfile = {
      id: playerId,
      username,
      level: 1,
      totalWagered: 0,
      totalWon: 0,
      gamesPlayed: 0,
      vipTier: 'bronze',
      joinedAt: new Date(),
      lastSeenAt: new Date(),
    };

    this.playerProfiles.set(playerId, profile);
    return profile;
  }

  /**
   * Get player profile
   */
  async getProfile(playerId: number): Promise<PlayerProfile | undefined> {
    return this.playerProfiles.get(playerId);
  }

  /**
   * Update player profile
   */
  async updateProfile(
    playerId: number,
    updates: Partial<PlayerProfile>
  ): Promise<PlayerProfile | undefined> {
    const profile = this.playerProfiles.get(playerId);
    if (!profile) return undefined;

    Object.assign(profile, updates);
    profile.lastSeenAt = new Date();

    return profile;
  }

  /**
   * Send friend request
   */
  async sendFriendRequest(
    playerId: number,
    targetId: number
  ): Promise<{ success: boolean; message: string }> {
    if (playerId === targetId) {
      return { success: false, message: 'Cannot friend yourself' };
    }

    // Check if already friends
    const existing = this.getFriendship(playerId, targetId);
    if (existing && existing.status === 'accepted') {
      return { success: false, message: 'Already friends' };
    }

    if (existing && existing.status === 'pending') {
      return { success: false, message: 'Friend request already sent' };
    }

    const friendship: Friend = {
      id: Math.random(),
      playerId,
      friendId: targetId,
      status: 'pending',
      createdAt: new Date(),
    };

    if (!this.friendships.has(playerId)) {
      this.friendships.set(playerId, []);
    }
    this.friendships.get(playerId)!.push(friendship);

    // Log friend request
    await writeAuditLog({
      actorId: playerId,
      actorRole: 'user',
      action: 'friend_request_sent',
      category: 'social',
      details: { targetId },
    });

    return { success: true, message: 'Friend request sent' };
  }

  /**
   * Accept friend request
   */
  async acceptFriendRequest(
    playerId: number,
    requesterId: number
  ): Promise<{ success: boolean; message: string }> {
    const friendship = this.getFriendship(requesterId, playerId);
    if (!friendship) {
      return { success: false, message: 'Friend request not found' };
    }

    if (friendship.status !== 'pending') {
      return { success: false, message: 'Request already processed' };
    }

    friendship.status = 'accepted';
    friendship.acceptedAt = new Date();

    // Log friend request acceptance
    await writeAuditLog({
      actorId: playerId,
      actorRole: 'user',
      action: 'friend_request_accepted',
      category: 'social',
      details: { requesterId },
    });

    return { success: true, message: 'Friend request accepted' };
  }

  /**
   * Reject friend request
   */
  async rejectFriendRequest(
    playerId: number,
    requesterId: number
  ): Promise<{ success: boolean; message: string }> {
    const friendships = this.friendships.get(requesterId) || [];
    const friendship = friendships.find((f) => f.friendId === playerId && f.status === 'pending');

    if (!friendship) {
      return { success: false, message: 'Friend request not found' };
    }

    // Remove the friendship
    const index = friendships.indexOf(friendship);
    if (index > -1) {
      friendships.splice(index, 1);
    }

    return { success: true, message: 'Friend request rejected' };
  }

  /**
   * Remove friend
   */
  async removeFriend(playerId: number, friendId: number): Promise<{ success: boolean; message: string }> {
    const friendships = this.friendships.get(playerId) || [];
    const friendship = friendships.find((f) => f.friendId === friendId && f.status === 'accepted');

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

    // Remove the friendship
    const index = friendships.indexOf(friendship);
    if (index > -1) {
      friendships.splice(index, 1);
    }

    return { success: true, message: 'Friend removed' };
  }

  /**
   * Get friends list
   */
  async getFriendsList(playerId: number): Promise<PlayerProfile[]> {
    const friendships = this.friendships.get(playerId) || [];
    const friends: PlayerProfile[] = [];

    for (const friendship of friendships) {
      if (friendship.status === 'accepted') {
        const friend = this.playerProfiles.get(friendship.friendId);
        if (friend) {
          friends.push(friend);
        }
      }
    }

    return friends;
  }

  /**
   * Get pending friend requests
   */
  async getPendingRequests(playerId: number): Promise<PlayerProfile[]> {
    const allFriendships = Array.from(this.friendships.values()).flat();
    const requests: PlayerProfile[] = [];

    for (const friendship of allFriendships) {
      if (friendship.friendId === playerId && friendship.status === 'pending') {
        const requester = this.playerProfiles.get(friendship.playerId);
        if (requester) {
          requests.push(requester);
        }
      }
    }

    return requests;
  }

  /**
   * Get leaderboard by type
   */
  async getLeaderboard(
    type: 'total_wagered' | 'total_won' | 'games_played' | 'level',
    limit: number = 100
  ): Promise<LeaderboardEntry[]> {
    const profiles = Array.from(this.playerProfiles.values());

    let sorted: PlayerProfile[];
    switch (type) {
      case 'total_wagered':
        sorted = profiles.sort((a, b) => b.totalWagered - a.totalWagered);
        break;
      case 'total_won':
        sorted = profiles.sort((a, b) => b.totalWon - a.totalWon);
        break;
      case 'games_played':
        sorted = profiles.sort((a, b) => b.gamesPlayed - a.gamesPlayed);
        break;
      case 'level':
        sorted = profiles.sort((a, b) => b.level - a.level);
        break;
    }

    return sorted.slice(0, limit).map((profile, index) => ({
      rank: index + 1,
      playerId: profile.id,
      username: profile.username,
      score: this.getLeaderboardScore(profile, type),
      vipTier: profile.vipTier,
      avatar: profile.avatar,
    }));
  }

  /**
   * Get player's leaderboard position
   */
  async getPlayerPosition(
    playerId: number,
    type: 'total_wagered' | 'total_won' | 'games_played' | 'level'
  ): Promise<{ rank: number; score: number; percentile: number } | null> {
    const leaderboard = await this.getLeaderboard(type, 10000);
    const entry = leaderboard.find((e) => e.playerId === playerId);

    if (!entry) {
      return null;
    }

    const percentile = ((leaderboard.length - entry.rank) / leaderboard.length) * 100;

    return {
      rank: entry.rank,
      score: entry.score,
      percentile,
    };
  }

  /**
   * Update player stats
   */
  async updatePlayerStats(
    playerId: number,
    updates: {
      totalWagered?: number;
      totalWon?: number;
      gamesPlayed?: number;
      level?: number;
      vipTier?: string;
    }
  ): Promise<void> {
    const profile = this.playerProfiles.get(playerId);
    if (!profile) return;

    if (updates.totalWagered !== undefined) {
      profile.totalWagered += updates.totalWagered;
    }
    if (updates.totalWon !== undefined) {
      profile.totalWon += updates.totalWon;
    }
    if (updates.gamesPlayed !== undefined) {
      profile.gamesPlayed += updates.gamesPlayed;
    }
    if (updates.level !== undefined) {
      profile.level = updates.level;
    }
    if (updates.vipTier !== undefined) {
      profile.vipTier = updates.vipTier;
    }

    profile.lastSeenAt = new Date();
  }

  /**
   * Get friendship status
   */
  private getFriendship(playerId: number, targetId: number): Friend | undefined {
    const friendships = this.friendships.get(playerId) || [];
    return friendships.find((f) => f.friendId === targetId);
  }

  /**
   * Get leaderboard score
   */
  private getLeaderboardScore(
    profile: PlayerProfile,
    type: 'total_wagered' | 'total_won' | 'games_played' | 'level'
  ): number {
    switch (type) {
      case 'total_wagered':
        return profile.totalWagered;
      case 'total_won':
        return profile.totalWon;
      case 'games_played':
        return profile.gamesPlayed;
      case 'level':
        return profile.level;
    }
  }

  /**
   * Search players
   */
  async searchPlayers(query: string, limit: number = 20): Promise<PlayerProfile[]> {
    const profiles = Array.from(this.playerProfiles.values());
    const filtered = profiles.filter((p) =>
      p.username.toLowerCase().includes(query.toLowerCase())
    );

    return filtered.slice(0, limit);
  }

  /**
   * Get player activity
   */
  async getPlayerActivity(playerId: number): Promise<{
    lastSeenAt: Date;
    totalFriends: number;
    gamesPlayedToday: number;
  }> {
    const profile = this.playerProfiles.get(playerId);
    if (!profile) {
      return { lastSeenAt: new Date(), totalFriends: 0, gamesPlayedToday: 0 };
    }

    const friends = await this.getFriendsList(playerId);

    return {
      lastSeenAt: profile.lastSeenAt,
      totalFriends: friends.length,
      gamesPlayedToday: 0, // Would be calculated from game history
    };
  }
}

export const socialManager = new SocialManager();
