import { Injectable, UnauthorizedException, BadRequestException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import * as bcrypt from 'bcrypt';
import { PrismaService } from '@common/prisma/prisma.service';
import { RedisService } from '@common/redis/redis.service';
import { RegisterDto, LoginDto } from './dto/auth.dto';

@Injectable()
export class AuthService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly jwtService: JwtService,
    private readonly configService: ConfigService,
    private readonly redis: RedisService,
  ) {}

  async register(dto: RegisterDto) {
    // 检查用户名是否已存在
    const existingUser = await this.prisma.user.findFirst({
      where: {
        OR: [
          { username: dto.username },
          { email: dto.email },
        ],
      },
    });

    if (existingUser) {
      throw new BadRequestException('用户名或邮箱已存在');
    }

    // 加密密码
    const passwordHash = await bcrypt.hash(dto.password, 10);

    // 创建用户
    const user = await this.prisma.user.create({
      data: {
        username: dto.username,
        email: dto.email,
        passwordHash,
        phone: dto.phone,
      },
      select: {
        id: true,
        username: true,
        email: true,
        avatarUrl: true,
        membershipLevel: true,
        createdAt: true,
      },
    });

    // 生成Token
    const tokens = await this.generateTokens(user.id, user.username);

    return {
      user,
      ...tokens,
    };
  }

  async login(dto: LoginDto) {
    // 查找用户
    const user = await this.prisma.user.findFirst({
      where: {
        OR: [
          { username: dto.username },
          { email: dto.username },
        ],
      },
    });

    if (!user) {
      throw new UnauthorizedException('用户名或密码错误');
    }

    // 验证密码
    const isPasswordValid = await bcrypt.compare(dto.password, user.passwordHash);
    if (!isPasswordValid) {
      throw new UnauthorizedException('用户名或密码错误');
    }

    // 检查用户状态
    if (!user.isActive) {
      throw new UnauthorizedException('账户已被禁用');
    }

    // 生成Token
    const tokens = await this.generateTokens(user.id, user.username);

    // 保存会话到Redis
    const ttl = parseInt(this.configService.get('jwt.expiresIn'), 10) || 3600;
    await this.redis.setSession(tokens.token, user.id, ttl);

    return {
      user: {
        id: user.id,
        username: user.username,
        email: user.email,
        avatarUrl: user.avatarUrl,
        membershipLevel: user.membershipLevel,
      },
      ...tokens,
    };
  }

  async logout(token: string) {
    await this.redis.deleteSession(token);
    return { message: '登出成功' };
  }

  async refreshToken(refreshToken: string) {
    try {
      const payload = this.jwtService.verify(refreshToken, {
        secret: this.configService.get('jwt.secret'),
      });

      const user = await this.prisma.user.findUnique({
        where: { id: payload.sub },
      });

      if (!user || !user.isActive) {
        throw new UnauthorizedException('用户不存在或已被禁用');
      }

      const tokens = await this.generateTokens(user.id, user.username);
      
      // 更新会话
      const ttl = parseInt(this.configService.get('jwt.expiresIn'), 10) || 3600;
      await this.redis.setSession(tokens.token, user.id, ttl);

      return tokens;
    } catch (error) {
      throw new UnauthorizedException('无效的刷新令牌');
    }
  }

  async getProfile(userId: number) {
    const user = await this.prisma.user.findUnique({
      where: { id: userId },
      select: {
        id: true,
        username: true,
        email: true,
        phone: true,
        avatarUrl: true,
        membershipLevel: true,
        createdAt: true,
      },
    });

    if (!user) {
      throw new UnauthorizedException('用户不存在');
    }

    return user;
  }

  async updateProfile(userId: number, data: Partial<{ phone: string; avatarUrl: string }>) {
    const user = await this.prisma.user.update({
      where: { id: userId },
      data,
      select: {
        id: true,
        username: true,
        email: true,
        phone: true,
        avatarUrl: true,
        membershipLevel: true,
      },
    });

    return user;
  }

  private async generateTokens(userId: number, username: string) {
    const payload = { sub: userId, username };
    
    const [token, refreshToken] = await Promise.all([
      this.jwtService.signAsync(payload),
      this.jwtService.signAsync(payload, {
        expiresIn: this.configService.get('jwt.refreshExpiresIn') || '7d',
      }),
    ]);

    return {
      token,
      refreshToken,
      expiresIn: parseInt(this.configService.get('jwt.expiresIn'), 10) || 3600,
    };
  }

  async validateUser(userId: number) {
    const user = await this.prisma.user.findUnique({
      where: { id: userId },
      select: {
        id: true,
        username: true,
        email: true,
        isActive: true,
        membershipLevel: true,
      },
    });

    if (!user || !user.isActive) {
      return null;
    }

    return user;
  }
}
