import { isAppUser } from '@api/helpers/device.helper';
import { AUTH_COOKIE_NAME, authCookieOptions } from '@api/helpers/cookie.helper';
import {
  Body,
  Controller,
  Headers,
  Param,
  Patch,
  Post,
  Req,
  Res,
} from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { plainToInstance } from 'class-transformer';
import { Request, Response } from 'express';
import {
  FcmTokenDto,
  IsAvaliableLoginIdParam,
  IsAvaliableLoginIdResponseDto,
  IsTrialResponseDto,
  LookupLoginIdDto,
  LookupLoginIdResponseDto,
  LookupPasswordDto,
  RefreshTokenDto,
  ResetPasswordDto,
  SignInDto,
  SignInResponseDto,
  SignUpDto,
} from './auth.dto';
import { AuthService } from './auth.service';

@ApiTags('인증')
@Controller('auth')
export class AuthController {
  constructor(private authService: AuthService) {}

  @ApiOperation({ summary: '회원가입' })
  @Post('signup')
  async signup(@Body() dto: SignUpDto) {
    const isTrial = await this.authService.signup(dto);
    return plainToInstance(IsTrialResponseDto, {
      isTrial,
    });
  }

  @ApiOperation({ summary: '로그인' })
  @Post('signin')
  async signin(
    @Body() dto: SignInDto,
    @Res({ passthrough: true }) res: Response,
    @Req() req: Request,
    @Headers('user-agent') userAgent: string,
  ) {
    let isApp = isAppUser(userAgent);

    const { accessToken, fc, refreshToken } = await this.authService.signin(
      dto,
      isApp,
    );

    //* 옛 _aT 잔재 제거 후 새 토큰 set (옵션 통일 — 누적/만료토큰 우선읽힘 방지)
    res.clearCookie(AUTH_COOKIE_NAME, authCookieOptions(req));
    res.cookie(AUTH_COOKIE_NAME, accessToken, authCookieOptions(req, true));

    const response = {
      fc: {
        id: fc.id,
        loginId: fc.loginId,
        memType: fc.memType,
        name: fc.name,
        phone: fc.phone,
        email: fc.email,
        agency: fc.agency,
        myReferralCode: fc.myReferralCode,
        memCreatedAt: fc.memCreatedAt,
        memPushEvent: fc.memPushEvent,
        accessToken, // 브릿지로 전달하기 위해 추가
      },
      refreshToken
    };

    console.log('📤 응답 데이터:', response);

    return response;
  }

  @ApiOperation({ summary: '아이디중복검사' })
  @Post(':loginId/avaliable')
  async isAvaliable(@Param() param: IsAvaliableLoginIdParam) {
    const doesExist = await this.authService.doesExist(param.loginId);
    return plainToInstance(IsAvaliableLoginIdResponseDto, {
      avaliable: !doesExist,
    });
  }

  @ApiOperation({ summary: '아이디찾기' })
  @Post('lookup-loginId')
  async lookupLoginId(@Body() dto: LookupLoginIdDto) {
    const loginId = await this.authService.lookupLoginId(dto);
    return plainToInstance(LookupLoginIdResponseDto, { loginId });
  }

  @ApiOperation({ summary: '비밀번호찾기' })
  @Post('lookup-password')
  async lookupPassword(@Body() dto: LookupPasswordDto) {
    await this.authService.lookupPassword(dto);
    return;
  }

  @ApiOperation({ summary: '새비밀번호설정' })
  @Patch('reset-password')
  async resetPassword(@Body() dto: ResetPasswordDto) {
    await this.authService.updatePassword(dto);
  }

  @ApiOperation({ summary: '로그아웃' })
  @Post('signout')
  async signout(
    @Res({ passthrough: true }) res: Response,
    @Req() req: Request,
    @Headers('user-agent') userAgent: string,
  ) {
    //* 앱환경 구분을 위해 네이티브 세팅한 userAgent값 검증
    let isApp = userAgent.includes('insuniverse');

    //* 앱환경에서 로그아웃시 DB에 저장되어있는 refreshToken 공백처리
    if (isApp) {
      await this.authService.signout(req);
    }

    //* set 과 동일 옵션으로 삭제해야 실제로 지워진다(옵션 불일치 시 옛 쿠키 잔존)
    res.clearCookie(AUTH_COOKIE_NAME, authCookieOptions(req));
    return;
  }

  @ApiOperation({ summary: 'FCM 토큰 저장' })
  @Post('fcm-token')
  async fcmToken(@Body() dto: FcmTokenDto) {
    await this.authService.updateFcmToken(dto);
  }

  @ApiOperation({ summary: '앱 자동로그인을 위한 refresh token 처리' })
  @Post('refresh')
  async refresh(
    @Body() dto: RefreshTokenDto,
    @Res({ passthrough: true }) res: Response,
    @Req() req: Request,
  ) {
    const { accessToken, fc, refreshToken } =
      await this.authService.refresh(dto);

    //* 옛 _aT 잔재 제거 후 새 토큰 set (옵션 통일)
    res.clearCookie(AUTH_COOKIE_NAME, authCookieOptions(req));
    res.cookie(AUTH_COOKIE_NAME, accessToken, authCookieOptions(req, true));

    return {
      fc: {
        id: fc.id,
        loginId: fc.loginId,
        memType: fc.memType,
        name: fc.name,
        phone: fc.phone,
        email: fc.email,
        agency: fc.agency,
        myReferralCode: fc.myReferralCode,
        memCreatedAt: fc.memCreatedAt,
        memPushEvent: fc.memPushEvent,
        accessToken, // 브릿지로 전달하기 위해 추가
      },
      refreshToken
    };
  }
}
