import { logger } from '@goodgo/logger';
import { Request, Response } from 'express';

import { auditService } from '../../core/events/audit.service';
import { getErrorMessage } from '../../utils/error-utils';
import { rbacService } from '../rbac/rbac.service';
import { sessionService } from '../session/session.service';
import { cookieService } from '../token/cookie.service';
import { jwtService } from '../token/jwt.service';

import { socialAuthService } from './social.service';

/**
 * EN: Social Auth Controller
 * VI: Controller xác thực mạng xã hội
 */
export class SocialAuthController {
  /**
   * EN: Initiate Google OAuth
   * VI: Bắt đầu OAuth Google
   */
  async googleAuth(req: Request, res: Response): Promise<void> {
    try {
      const { GoogleProvider } = await import('./providers/google.provider');
      const provider = new GoogleProvider();
      const url = provider.getAuthorizationUrl();
      res.redirect(url);
    } catch (error: unknown) {
      logger.error('Google auth initiation failed', { error });
      res.status(500).json({
        success: false,
        error: {
          code: 'SOCIAL_AUTH_FAILED',
          message: 'Failed to initiate Google authentication',
        },
      });
    }
  }

  /**
   * EN: Google OAuth callback
   * VI: Callback OAuth Google
   */
  async googleCallback(req: Request, res: Response): Promise<void> {
    try {
      const { code } = req.query;
      if (!code || typeof code !== 'string') {
        res.status(400).json({
          success: false,
          error: { code: 'INVALID_CODE', message: 'Authorization code required' },
        });
        return;
      }

      const result = await socialAuthService.authenticate('GOOGLE', code);
      
      // Generate tokens
      const roles = await rbacService.getUserRoles(result.user.id);
      const permissions = await rbacService.getUserPermissions(result.user.id);
      
      const tokens = await jwtService.generateTokenSet(
        {
          id: result.user.id,
          email: result.user.email,
          emailVerified: result.user.emailVerified,
          username: result.user.username || undefined,
          updatedAt: result.user.updatedAt || new Date(),
        },
        roles,
        permissions
      );

      // Create session
      await sessionService.createSession(result.user.id, req);

      // Set cookies
      cookieService.setAuthCookies(res, tokens);

      // Audit log
      await auditService.logFromRequest(req, 'SOCIAL_LOGIN', {
        userId: result.user.id,
        success: true,
        metadata: { provider: 'GOOGLE' },
      });

      // Redirect to frontend
      res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/callback?token=${tokens.accessToken}`);
    } catch (error: unknown) {
      logger.error('Google callback failed', { error });
      res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/error?message=${encodeURIComponent(getErrorMessage(error))}`);
    }
  }

  /**
   * EN: Initiate Facebook OAuth
   * VI: Bắt đầu OAuth Facebook
   */
  async facebookAuth(req: Request, res: Response): Promise<void> {
    try {
      const { FacebookProvider } = await import('./providers/facebook.provider');
      const provider = new FacebookProvider();
      const url = provider.getAuthorizationUrl();
      res.redirect(url);
    } catch (error: unknown) {
      logger.error('Facebook auth initiation failed', { error });
      res.status(500).json({
        success: false,
        error: {
          code: 'SOCIAL_AUTH_FAILED',
          message: 'Failed to initiate Facebook authentication',
        },
      });
    }
  }

  /**
   * EN: Facebook OAuth callback
   * VI: Callback OAuth Facebook
   */
  async facebookCallback(req: Request, res: Response): Promise<void> {
    try {
      const { code } = req.query;
      if (!code || typeof code !== 'string') {
        res.status(400).json({
          success: false,
          error: { code: 'INVALID_CODE', message: 'Authorization code required' },
        });
        return;
      }

      const result = await socialAuthService.authenticate('FACEBOOK', code);
      
      const roles = await rbacService.getUserRoles(result.user.id);
      const permissions = await rbacService.getUserPermissions(result.user.id);
      
      const tokens = await jwtService.generateTokenSet(
        {
          id: result.user.id,
          email: result.user.email,
          emailVerified: result.user.emailVerified,
          username: result.user.username || undefined,
          updatedAt: result.user.updatedAt || new Date(),
        },
        roles,
        permissions
      );

      await sessionService.createSession(result.user.id, req);
      cookieService.setAuthCookies(res, tokens);

      await auditService.logFromRequest(req, 'SOCIAL_LOGIN', {
        userId: result.user.id,
        success: true,
        metadata: { provider: 'FACEBOOK' },
      });

      res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/callback?token=${tokens.accessToken}`);
    } catch (error: unknown) {
      logger.error('Facebook callback failed', { error });
      res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/error?message=${encodeURIComponent(getErrorMessage(error))}`);
    }
  }

  /**
   * EN: Initiate GitHub OAuth
   * VI: Bắt đầu OAuth GitHub
   */
  async githubAuth(req: Request, res: Response): Promise<void> {
    try {
      const { GitHubProvider } = await import('./providers/github.provider');
      const provider = new GitHubProvider();
      const url = provider.getAuthorizationUrl();
      res.redirect(url);
    } catch (error: unknown) {
      logger.error('GitHub auth initiation failed', { error });
      res.status(500).json({
        success: false,
        error: {
          code: 'SOCIAL_AUTH_FAILED',
          message: 'Failed to initiate GitHub authentication',
        },
      });
    }
  }

  /**
   * EN: GitHub OAuth callback
   * VI: Callback OAuth GitHub
   */
  async githubCallback(req: Request, res: Response): Promise<void> {
    try {
      const { code } = req.query;
      if (!code || typeof code !== 'string') {
        res.status(400).json({
          success: false,
          error: { code: 'INVALID_CODE', message: 'Authorization code required' },
        });
        return;
      }

      const result = await socialAuthService.authenticate('GITHUB', code);
      
      const roles = await rbacService.getUserRoles(result.user.id);
      const permissions = await rbacService.getUserPermissions(result.user.id);
      
      const tokens = await jwtService.generateTokenSet(
        {
          id: result.user.id,
          email: result.user.email,
          emailVerified: result.user.emailVerified,
          username: result.user.username || undefined,
          updatedAt: result.user.updatedAt || new Date(),
        },
        roles,
        permissions
      );

      await sessionService.createSession(result.user.id, req);
      cookieService.setAuthCookies(res, tokens);

      await auditService.logFromRequest(req, 'SOCIAL_LOGIN', {
        userId: result.user.id,
        success: true,
        metadata: { provider: 'GITHUB' },
      });

      res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/callback?token=${tokens.accessToken}`);
    } catch (error: unknown) {
      logger.error('GitHub callback failed', { error });
      res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/error?message=${encodeURIComponent(getErrorMessage(error))}`);
    }
  }
}

export const socialAuthController = new SocialAuthController();
