import { logger } from '@goodgo/logger';
import { PrismaClient, Provider } from '@prisma/client';

import { getPrismaClient } from '../../config/database.config';
import { createCircuitBreaker } from '../../modules/common/circuit-breaker';
import { SocialAuthResponse, SocialAccountResponse, UserResponse } from '../../types/auth.types';

import { FacebookProvider } from './providers/facebook.provider';
import { GitHubProvider } from './providers/github.provider';
import { GoogleProvider } from './providers/google.provider';


/**
 * EN: Social profile interface
 * VI: Interface cho profile mạng xã hội
 */
export interface SocialProfile {
  id: string;
  email: string;
  name?: string;
  avatar?: string;
  username?: string;
}

/**
 * EN: Social Auth Service with circuit breaker
 * VI: Service xác thực mạng xã hội với circuit breaker
 */
export class SocialAuthService {
  private prisma: PrismaClient;
  private googleProvider: GoogleProvider;
  private facebookProvider: FacebookProvider;
  private githubProvider: GitHubProvider;

  constructor() {
    this.prisma = getPrismaClient();
    this.googleProvider = new GoogleProvider();
    this.facebookProvider = new FacebookProvider();
    this.githubProvider = new GitHubProvider();
  }

  /**
   * EN: Get provider instance
   * VI: Lấy instance provider
   */
  private getProvider(provider: Provider) {
    switch (provider) {
      case 'GOOGLE':
        return this.googleProvider;
      case 'FACEBOOK':
        return this.facebookProvider;
      case 'GITHUB':
        return this.githubProvider;
      default:
        throw new Error(`Unsupported provider: ${provider}`);
    }
  }

  /**
   * EN: Handle social authentication
   * VI: Xử lý xác thực mạng xã hội
   */
  async authenticate(
    provider: Provider,
    code: string,
    redirectUri?: string
  ): Promise<SocialAuthResponse> {
    const providerInstance = this.getProvider(provider);

    // Use circuit breaker for external API calls
    const circuitBreaker = createCircuitBreaker(
      async () => {
        return await providerInstance.getProfile(code, redirectUri);
      },
      `social-auth-${provider}`,
      {
        timeout: 3000, // 3s timeout
        errorThresholdPercentage: 50, // 50% error rate
        resetTimeout: 30000, // Reset after 30s
      }
    );

    let profile: SocialProfile;
    try {
      profile = await circuitBreaker.fire();
    } catch (error) {
      logger.error('Social auth provider error', { provider, error });
      // Try to get cached profile
      const cached = await this.getCachedProfile(provider, code);
      if (cached) {
        logger.warn('Using cached profile', { provider });
        profile = cached;
      } else {
        throw new Error(`Failed to authenticate with ${provider}`);
      }
    }

    // Find or create social account
    const socialAccount = await this.findOrCreateSocialAccount(provider, profile);

    // Find or create user
    const user = await this.findOrCreateUser(socialAccount);

    if (!user) {
      throw new Error('Failed to find or create user');
    }

    return {
      user: {
        id: user.id,
        email: user.email,
        username: user.username,
        emailVerified: user.emailVerified,
        isActive: user.isActive,
        mfaEnabled: user.mfaEnabled,
      },
      socialAccount: {
        id: socialAccount.id,
        userId: socialAccount.userId,
        provider: socialAccount.provider,
        providerId: socialAccount.providerId,
        email: socialAccount.email,
        name: socialAccount.name,
        avatar: socialAccount.avatar,
      },
    };
  }

  /**
   * EN: Find or create social account
   * VI: Tìm hoặc tạo tài khoản mạng xã hội
   */
  private async findOrCreateSocialAccount(
    provider: Provider,
    profile: SocialProfile
  ): Promise<SocialAccountResponse> {
    // Note: If storing accessToken/refreshToken in the future, 
    // ensure they are encrypted using encryptionService before saving.
    const existing = await this.prisma.socialAccount.findUnique({
      where: {
        provider_providerId: {
          provider,
          providerId: profile.id,
        },
      },
    });

    if (existing) {
      // Update profile info
      const updated = await this.prisma.socialAccount.update({
        where: { id: existing.id },
        data: {
          email: profile.email,
          name: profile.name,
          avatar: profile.avatar,
        },
      });
      return {
        id: updated.id,
        userId: updated.userId,
        provider: updated.provider,
        providerId: updated.providerId,
        email: updated.email || profile.email || '',
        name: updated.name || null,
        avatar: updated.avatar || null,
      };
    }

    // Check if user with this email exists
    const existingUser = await this.prisma.user.findUnique({
      where: { email: profile.email },
    });

    if (existingUser) {
      // Link social account to existing user
      const created = await this.prisma.socialAccount.create({
        data: {
          userId: existingUser.id,
          provider,
          providerId: profile.id,
          email: profile.email,
          name: profile.name,
          avatar: profile.avatar,
        },
      });
      return {
        id: created.id,
        userId: created.userId,
        provider: created.provider,
        providerId: created.providerId,
        email: created.email || profile.email || '',
        name: created.name || null,
        avatar: created.avatar || null,
      };
    }

    // Create new user and social account
    const newUser = await this.prisma.user.create({
      data: {
        email: profile.email,
        username: profile.username || profile.email.split('@')[0],
        emailVerified: true, // Social accounts are pre-verified
        isActive: true,
      },
    });

    const created = await this.prisma.socialAccount.create({
      data: {
        userId: newUser.id,
        provider,
        providerId: profile.id,
        email: profile.email,
        name: profile.name,
        avatar: profile.avatar,
      },
    });
    return {
      id: created.id,
      userId: created.userId,
      provider: created.provider,
      providerId: created.providerId,
      email: created.email || profile.email || '',
      name: created.name,
      avatar: created.avatar,
    };
  }

  /**
   * EN: Find or create user
   * VI: Tìm hoặc tạo người dùng
   */
  private async findOrCreateUser(socialAccount: SocialAccountResponse): Promise<UserResponse | null> {
    const user = await this.prisma.user.findUnique({
      where: { id: socialAccount.userId },
      include: {
        userRoles: {
          include: { role: true },
        },
      },
    });

    if (!user) {
      return null;
    }

    return {
      id: user.id,
      email: user.email,
      username: user.username,
      emailVerified: user.emailVerified,
      isActive: user.isActive,
      mfaEnabled: user.mfaEnabled,
    };
  }

  /**
   * EN: Get cached profile (fallback)
   * VI: Lấy profile đã cache (fallback)
   */
  private async getCachedProfile(
    _provider: Provider,
    _code: string
  ): Promise<SocialProfile | null> {
    // In production, implement proper caching
    return null;
  }

  /**
   * EN: Unlink social account
   * VI: Hủy liên kết tài khoản mạng xã hội
   */
  async unlinkAccount(userId: string, provider: Provider): Promise<void> {
    await this.prisma.socialAccount.deleteMany({
      where: {
        userId,
        provider,
      },
    });

    logger.info('Social account unlinked', { userId, provider });
  }
}

export const socialAuthService = new SocialAuthService();
