import { Injectable, UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcryptjs';
import { PrismaService } from '../prisma/prisma.service';
import { LoginDto } from './auth.dto';
import { AuthUser } from '../../common/current-user.decorator';

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

  async login(dto: LoginDto) {
    const isPlatformLogin = dto.tenantCode === 'platform';
    const tenant = isPlatformLogin
      ? null
      : await this.prisma.tenant.findUnique({
          where: { code: dto.tenantCode },
        });
    if (!isPlatformLogin && !tenant?.enabled) {
      throw new UnauthorizedException('租户不存在或已停用');
    }

    const user = await this.prisma.user.findFirst({
      where: { username: dto.username, tenantId: tenant?.id ?? null },
      include: {
        tenant: true,
        roles: { include: { role: { include: { permissions: { include: { permission: true } }, regionScopes: true } } } },
        regionScopes: true,
      },
    });

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

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

    const payload = {
      sub: user.id,
      username: user.username,
      tenantId: tenant?.id ?? null,
      tenantCode: tenant?.code ?? 'platform',
      roles: user.roles.map((item) => item.role.code),
      permissions: [...new Set(user.roles.flatMap((item) => item.role.permissions.map((rp) => rp.permission.code)))],
      regionIds: [
        ...new Set([
          ...user.regionScopes.map((scope) => scope.regionId),
          ...user.roles.flatMap((item) => item.role.regionScopes.map((scope) => scope.regionId)),
        ]),
      ],
    };

    return {
      accessToken: await this.jwtService.signAsync(payload),
      refreshToken: await this.jwtService.signAsync(payload, {
        expiresIn: this.configService.get('REFRESH_TOKEN_EXPIRES_IN') ?? '7d',
      }),
      user: {
        id: user.id,
        username: user.username,
        name: user.name,
        tenant: {
          id: tenant?.id ?? null,
          code: tenant?.code ?? 'platform',
          name: tenant?.name ?? '平台管理',
        },
        roles: payload.roles,
        permissions: payload.permissions,
        regionIds: payload.regionIds,
      },
    };
  }

  async refresh(refreshToken: string) {
    try {
      const payload = await this.jwtService.verifyAsync(refreshToken);
      const { exp, iat, ...rest } = payload;
      return {
        accessToken: await this.jwtService.signAsync(rest),
      };
    } catch {
      throw new UnauthorizedException('刷新令牌无效');
    }
  }

  async changePassword(user: AuthUser, dto: { oldPassword: string; newPassword: string }) {
    const account = await this.prisma.user.findUnique({ where: { id: user.sub } });
    if (!account) {
      throw new UnauthorizedException('用户不存在');
    }

    const valid = await bcrypt.compare(dto.oldPassword, account.passwordHash);
    if (!valid) {
      throw new UnauthorizedException('原密码错误');
    }

    await this.prisma.user.update({
      where: { id: user.sub },
      data: { passwordHash: await bcrypt.hash(dto.newPassword, 10) },
    });

    return { success: true };
  }
}
