
import { Public, User } from '@hed-hog/api';
import { Locale } from '@hed-hog/api-locale';
import { user_account_provider_52222e2ecb_enum } from '@hed-hog/api-prisma';
import {
    Body,
    Controller,
    Delete,
    Get,
    Headers,
    Ip,
    Logger,
    Param,
    Query,
    Res,
} from '@nestjs/common';
import { SettingService } from '../setting/setting.service';
import { OAuthService } from './oauth.service';

@Controller('oauth')
export class OAuthController {
  private readonly logger = new Logger(OAuthController.name);

  constructor(private readonly service: OAuthService, private readonly settingService: SettingService) {}

  private logOAuthRequest(
    action: string,
    provider: string,
    {
      locale,
      origin,
      referer,
      host,
      ipAddress,
      userAgent,
      code,
    }: {
      locale?: string;
      origin?: string;
      referer?: string;
      host?: string;
      ipAddress?: string;
      userAgent?: string;
      code?: string;
    },
  ) {
    const summarizedUserAgent = userAgent
      ? userAgent.length > 120
        ? `${userAgent.slice(0, 117)}...`
        : userAgent
      : 'n/a';

    this.logger.log(
      `OAuth ${action}: provider=${provider} locale=${locale ?? 'n/a'} origin=${origin ?? 'n/a'} referer=${referer ?? 'n/a'} host=${host ?? 'n/a'} ip=${ipAddress ?? 'n/a'} hasCode=${code ? 'yes' : 'no'} codeLength=${code?.length ?? 0} userAgent="${summarizedUserAgent}"`,
    );
  }

  @Public()
  @Get('github/callback')
  async githubCallback(
    @Query('code') code: string,
    @Query('state') state: string,
    @Res() res,
  ) {
    const type = state || 'login';
    const { url: frontendURL = '' } = await this.settingService.getSettingValues(['url']);
    const redirectURL = `${frontendURL}/callback/github/${type}?code=${encodeURIComponent(code)}`;
    return res.redirect(redirectURL);
  }

  @Public()
  @Get(':provider/login')
  async login(
    @Headers('origin') origin: string,
    @Headers('referer') referer: string,
    @Headers('host') host: string,
    @Param('provider') provider: string,
    @Res() res,
  ) {
    this.logOAuthRequest('login-init', provider, { origin, referer, host });

    const url = await this.service.getAuthUrl(
      provider as user_account_provider_52222e2ecb_enum,
      `/callback/${provider}/login`,
    );
    return res.redirect(url);
  }


  @Public()
  @Get(':provider/register')
  async register(@Param('provider') provider: string, @Res() res) {
    const url = await this.service.getAuthUrl(
      provider as user_account_provider_52222e2ecb_enum,
      `/callback/${provider}/register`,
    );
    return res.redirect(url);
  }


  @Public()
  @Get(':provider/connect')
  async connect(@Param('provider') provider: string, @Res() res) {
    const url = this.service.getAuthUrl(
      provider as user_account_provider_52222e2ecb_enum,
      `/callback/${provider}/connect`,
    );
    return res.redirect(url);
  }


  @Public()
  @Get(':provider/callback/login')
  async callbackLogin(
    @Locale() locale: string,
    @Ip() ipAddress: string,
    @Headers('user-agent') userAgent: string,
    @Headers('origin') origin: string,
    @Headers('referer') referer: string,
    @Headers('host') host: string,
    @Headers('x-forwarded-host') forwardedHost: string,
    @Param('provider') provider: string,
    @Query('code') code: string,
    @Res({ passthrough: true }) res,
  ) {
    this.logOAuthRequest('callback-login', provider, {
      locale,
      origin,
      referer,
      host: forwardedHost || host,
      ipAddress,
      userAgent,
      code,
    });

    return this.service.handleCallback({ res, locale, ipAddress, userAgent, provider: provider as user_account_provider_52222e2ecb_enum, code, type: 'login' });
  }


  @Public()
  @Get(':provider/callback/register')
  async callbackRegister(
    @Locale() locale: string,
    @Ip() ipAddress: string,
    @Headers('user-agent') userAgent: string,
    @Param('provider') provider: string,
    @Query('code') code: string,
    @Res({ passthrough: true }) res,
  ) {
    return this.service.handleCallback({ res, locale, ipAddress, userAgent, provider: provider as user_account_provider_52222e2ecb_enum, code, type: 'register' });
  }


  @Get(':provider/callback/connect')
  async callbackConnect(
    @Locale() locale: string,
    @Ip() ipAddress: string,
    @Headers('user-agent') userAgent: string,
    @User() { id },
    @Param('provider') provider: string,
    @Query('code') code: string,
    @Res({ passthrough: true }) res,
  ) {
    return this.service.handleCallback({ res, locale, ipAddress, userAgent, provider: provider as user_account_provider_52222e2ecb_enum, code, type: 'connect', userId: id });
  }


  @Delete(':provider')
  async disconnect(
    @Locale() locale: string,
    @Ip() ipAddress: string,
    @Headers('user-agent') userAgent: string,
    @Param('provider') provider: string,
    @Body('email') email: string,
    @Res({ passthrough: true }) res,
  ) {
    return this.service.handleCallback({ res, locale, ipAddress, userAgent, provider: provider as user_account_provider_52222e2ecb_enum, email, type: 'disconnect' });
  }
}
