import { Controller, Post, Body, Get, Param, UseGuards, Request, Inject, BadRequestException, UnauthorizedException } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { AuthService } from '../../../application/services/auth.service';
import { REDIS_CLIENT } from '../../../infrastructure/redis/redis.provider';
import Redis from 'ioredis';

@Controller('api/v1/auth')
export class AuthController {
  constructor(
    private readonly authService: AuthService,
    @Inject(REDIS_CLIENT) private readonly redis: Redis,
  ) {}

  @Post('login')
  async login(
    @Body() body: { identifier?: string; email?: string; phone?: string; password: string },
  ) {
    const identifier = body.identifier || body.email || body.phone;
    if (!identifier) {
      throw new Error('Email or phone is required');
    }
    return this.authService.login(identifier, body.password);
  }

  /**
   * Register a new enterprise account.
   * Supports email or phone as the login identifier.
   * If companyName is provided, creates a new tenant (self-service registration).
   * Phone registration requires a valid OTP (smsCode).
   */
  @Post('register')
  async register(
    @Body()
    body: {
      email?: string;
      phone?: string;
      smsCode?: string;
      password: string;
      name: string;
      companyName?: string;
    },
  ) {
    // Verify OTP when registering with phone
    if (body.phone) {
      const phone = body.phone.trim();
      if (!body.smsCode) throw new BadRequestException('手机注册需要验证码');
      const otpKey = `sms:otp:${phone}`;
      const stored = await this.redis.get(otpKey);
      if (!stored || stored !== body.smsCode.trim()) {
        throw new BadRequestException('验证码错误或已过期');
      }
      // Consume the OTP immediately
      await this.redis.del(otpKey);
    }

    return this.authService.register(
      body.password,
      body.name,
      body.companyName,
      body.email,
      body.phone,
    );
  }

  /**
   * Login with phone number + OTP (passwordless).
   * POST /api/v1/auth/login/otp
   */
  @Post('login/otp')
  async loginWithOtp(@Body() body: { phone: string; smsCode: string }) {
    const phone = (body.phone || '').trim();
    const code = (body.smsCode || '').trim();
    if (!phone || !code) throw new BadRequestException('手机号和验证码不能为空');

    const otpKey = `sms:otp:${phone}`;
    const stored = await this.redis.get(otpKey);
    if (!stored || stored !== code) {
      throw new BadRequestException('验证码错误或已过期');
    }
    await this.redis.del(otpKey);

    return this.authService.loginByPhone(phone);
  }

  /**
   * Validate an invitation token (public endpoint).
   */
  @Get('invite/:token')
  async validateInvite(@Param('token') token: string) {
    return this.authService.validateInvite(token);
  }

  /**
   * Accept an invitation and create a user account (public endpoint).
   */
  @Post('accept-invite')
  async acceptInvite(
    @Body() body: { token: string; password: string; name: string },
  ) {
    return this.authService.acceptInvite(body.token, body.password, body.name);
  }

  @Get('profile')
  @UseGuards(AuthGuard('jwt'))
  async getProfile(@Request() req: any) {
    return req.user;
  }

  @Post('refresh')
  async refreshToken(@Body() body: { refreshToken: string }) {
    return this.authService.refreshToken(body.refreshToken);
  }

  @Post('api-keys')
  @UseGuards(AuthGuard('jwt'))
  async createApiKey(@Request() req: any, @Body() body: { name: string }) {
    return this.authService.createApiKey(
      req.user.userId,
      req.user.tenantId,
      body.name,
    );
  }

  /** GET /api/v1/auth/my-org — tenant info + member list for the current user's tenant */
  @Get('my-org')
  @UseGuards(AuthGuard('jwt'))
  async getMyOrg(@Request() req: any) {
    const slug = req.user?.tenantId;
    if (!slug) throw new UnauthorizedException('No tenant context');
    return this.authService.getMyOrg(slug);
  }

  /** GET /api/v1/auth/my-org/invites */
  @Get('my-org/invites')
  @UseGuards(AuthGuard('jwt'))
  async getMyOrgInvites(@Request() req: any) {
    const slug = req.user?.tenantId;
    if (!slug) throw new UnauthorizedException('No tenant context');
    return this.authService.listInvites(slug);
  }

  /** POST /api/v1/auth/my-org/invite */
  @Post('my-org/invite')
  @UseGuards(AuthGuard('jwt'))
  async createMyOrgInvite(
    @Request() req: any,
    @Body() body: { email: string; role?: string },
  ) {
    const slug = req.user?.tenantId;
    const userId = req.user?.sub || req.user?.id;
    if (!slug) throw new UnauthorizedException('No tenant context');
    return this.authService.createInvite(slug, body.email, body.role || 'viewer', userId);
  }
}
