import {
  Body,
  Controller,
  Get,
  Logger,
  Patch,
  Post,
  Query,
  Req,
  UseGuards,
} from '@nestjs/common';
import { ApiBearerAuth, ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { AuthService } from './auth.service';
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
import { UserRole } from '@prisma/client';
import type { Request } from 'express';
import { UpdateMyProfileDto } from '../users/dto/update-my-profile.dto';
import { UpdateMyLocationDto } from '../users/dto/update-my-location.dto';
import { BootstrapSuperadminDto } from './dto/bootstrap-superadmin.dto';
import { PasswordLoginDto } from './dto/password-login.dto';
import { OtpRequestDto } from './dto/otp-request.dto';
import { OtpVerifyDto } from './dto/otp-verify.dto';
import { RegisterStoreDto } from './dto/register-store.dto';
import { PasswordResetRequestDto } from './dto/password-reset-request.dto';
import { PasswordResetVerifyDto } from './dto/password-reset-verify.dto';
import { PasswordResetConfirmDto } from './dto/password-reset-confirm.dto';
import { RegisterStoreMeDto } from './dto/register-store-me.dto';

type AuthedRequest = Request & {
  user?: { id: string; role: UserRole; shopId?: string | null };
};

@ApiTags('auth')
@Controller('auth')
export class AuthController {
  private readonly logger = new Logger(AuthController.name);
  constructor(private readonly auth: AuthService) {}

  @Post('bootstrap/superadmin')
  @ApiOkResponse({
    description: 'Creates the first superadmin (only if none exists)',
  })
  bootstrapSuperadmin(@Body() dto: BootstrapSuperadminDto) {
    return this.auth.bootstrapSuperadmin(dto);
  }

  @Post('login/password')
  @ApiOkResponse({
    description:
      'Email/password login (staff). Clients can restrict via dto.roles allow-list.',
  })
  loginWithPassword(@Body() dto: PasswordLoginDto) {
    return this.auth.loginWithPassword(dto);
  }

  @Post('register-store')
  @ApiOkResponse({
    description:
      'Self register store + admin in PENDING state (requires approval)',
  })
  registerStore(@Req() req: Request, @Body() dto: RegisterStoreDto) {
    const origin = (req.headers?.origin ?? '').toString().trim();
    const referer = (req.headers?.referer ?? req.headers?.referrer ?? '')
      .toString()
      .trim();
    let portalPublicUrl: string | null = origin || null;
    if (!portalPublicUrl && referer) {
      try {
        portalPublicUrl = new URL(referer).origin;
      } catch {
        portalPublicUrl = null;
      }
    }
    return this.auth.registerStore(dto, portalPublicUrl);
  }

  @Post('register-store/me')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('bearer')
  @ApiOkResponse({
    description:
      'Register store for the currently authenticated user (mobile user → merchant). Upgrades role and attaches a shop.',
  })
  registerStoreForMe(
    @Req() req: AuthedRequest,
    @Body() dto: RegisterStoreMeDto,
  ) {
    const origin = (req.headers?.origin ?? '').toString().trim();
    const referer = (req.headers?.referer ?? req.headers?.referrer ?? '')
      .toString()
      .trim();
    let portalPublicUrl: string | null = origin || null;
    if (!portalPublicUrl && referer) {
      try {
        portalPublicUrl = new URL(referer).origin;
      } catch {
        portalPublicUrl = null;
      }
    }
    return this.auth.registerStoreForMe(req.user!.id, dto, portalPublicUrl);
  }

  @Get('register-store/available')
  @ApiOkResponse({
    description: 'Checks if email/phone is available for store registration',
  })
  registerStoreAvailable(
    @Query('email') email?: string,
    @Query('phone') phone?: string,
  ) {
    return this.auth.registerStoreAvailable({ email, phone });
  }

  @Post('otp/request')
  @ApiOkResponse({ description: 'Request OTP for mobile login' })
  requestOtp(@Body() dto: OtpRequestDto) {
    return this.auth.requestOtp(dto);
  }

  @Post('otp/verify')
  @ApiOkResponse({ description: 'Verify OTP and return access token' })
  verifyOtp(@Body() dto: OtpVerifyDto) {
    return this.auth.verifyOtp(dto);
  }

  @Post('password-reset/request')
  @ApiOkResponse({
    description: 'Request a 5-minute password reset link (no email for now)',
  })
  requestPasswordReset(@Body() dto: PasswordResetRequestDto) {
    return this.auth.requestPasswordReset(dto);
  }

  @Post('password-reset/verify')
  @ApiOkResponse({ description: 'Verify password reset token validity' })
  verifyPasswordReset(@Body() dto: PasswordResetVerifyDto) {
    return this.auth.verifyPasswordReset(dto);
  }

  @Post('password-reset/confirm')
  @ApiOkResponse({ description: 'Confirm password reset and update password' })
  confirmPasswordReset(@Body() dto: PasswordResetConfirmDto) {
    return this.auth.confirmPasswordReset(dto);
  }

  @Post('logout')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('bearer')
  logout(@Req() req: Request & { user?: { id?: string } }) {
    return this.auth.logout(req.user?.id);
  }

  @Get('me')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('bearer')
  async me(@Req() req: Request & { user?: unknown }) {
    const u = req.user as any;
    this.logger.log(
      `me: id=${u?.id ?? u?.sub ?? 'unknown'} role=${u?.role ?? 'unknown'}`,
    );
    return this.auth.finalizeMeResponse(u);
  }

  /** Mobile app — dedicated paths next to OTP (POST only; same AuthService as login). */
  @Post('customer/profile')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('bearer')
  @ApiOkResponse({ description: 'Update customer name / email (onboarding)' })
  postCustomerProfile(
    @Req() req: AuthedRequest,
    @Body() dto: UpdateMyProfileDto,
  ) {
    return this.auth.updateMyCustomerProfile(req.user!.id, dto);
  }

  @Post('customer/location')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('bearer')
  @ApiOkResponse({ description: 'Store last known coordinates' })
  postCustomerLocation(
    @Req() req: AuthedRequest,
    @Body() dto: UpdateMyLocationDto,
  ) {
    return this.auth.updateMyCustomerLocation(req.user!.id, dto);
  }

  @Patch('me/profile')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('bearer')
  patchMyProfile(@Req() req: AuthedRequest, @Body() dto: UpdateMyProfileDto) {
    return this.auth.updateMyCustomerProfile(req.user!.id, dto);
  }

  @Post('me/profile')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('bearer')
  postMeProfileAlias(
    @Req() req: AuthedRequest,
    @Body() dto: UpdateMyProfileDto,
  ) {
    return this.auth.updateMyCustomerProfile(req.user!.id, dto);
  }

  @Patch('me/location')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('bearer')
  patchMyLocation(@Req() req: AuthedRequest, @Body() dto: UpdateMyLocationDto) {
    return this.auth.updateMyCustomerLocation(req.user!.id, dto);
  }

  @Post('me/location')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth('bearer')
  postMeLocationAlias(
    @Req() req: AuthedRequest,
    @Body() dto: UpdateMyLocationDto,
  ) {
    return this.auth.updateMyCustomerLocation(req.user!.id, dto);
  }
}
