import {
  Injectable,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import * as bcrypt from 'bcrypt';

@Injectable()
export class UsersService {
  constructor(private prisma: PrismaService) {}

  async create(createUserDto: CreateUserDto, tenantId: number) {
    const hashedPassword = await bcrypt.hash(createUserDto.password, 10);
    const { roleIds, ...userData } = createUserDto;

    // 验证角色是否属于该租户
    if (roleIds && roleIds.length > 0) {
      const roles = await this.prisma.role.findMany({
        where: {
          id: { in: roleIds },
          tenantId,
        },
      });
      if (roles.length !== roleIds.length) {
        throw new NotFoundException('部分角色不存在或不属于该租户');
      }
    }

    return this.prisma.user.create({
      data: {
        ...userData,
        tenantId,
        password: hashedPassword,
        roles:
          roleIds && roleIds.length > 0
            ? {
                create: roleIds.map((roleId) => ({
                  roleId,
                })),
              }
            : undefined,
      },
      include: {
        roles: {
          include: {
            role: true,
          },
        },
      },
    });
  }

  /**
   * 查询用户列表
   * isSuperTenant=true 时跨租户查询全部用户，支持 userType/filterTenantId/userSource/status 筛选
   */
  async findAll(params: {
    page?: number;
    pageSize?: number;
    tenantId?: number;
    keyword?: string;
    isSuperTenant?: boolean;
    userType?: string;
    filterTenantId?: number;
    userSource?: string;
    status?: string;
  }) {
    const {
      page = 1,
      pageSize = 10,
      tenantId,
      keyword,
      isSuperTenant = false,
      userType,
      filterTenantId,
      userSource,
      status,
    } = params;
    const skip = (page - 1) * pageSize;
    const where: any = { validState: 1 };

    // 超管跨租户查询：不按 tenantId 过滤，用 userType/filterTenantId 代替
    if (isSuperTenant) {
      if (userType) {
        const tenantCondition = this.buildTenantConditionByUserType(userType);
        if (tenantCondition) {
          where.tenant = tenantCondition;
        }
      }
      if (filterTenantId) {
        where.tenantId = filterTenantId;
      }
      if (userSource) {
        where.userSource = userSource;
      }
      if (status) {
        where.status = status;
      }
    } else {
      // 普通租户：按 tenantId 过滤
      if (tenantId) {
        where.tenantId = tenantId;
      }
    }

    // 关键字搜索
    if (keyword) {
      where.OR = [
        { username: { contains: keyword } },
        { nickname: { contains: keyword } },
        { email: { contains: keyword } },
        { phone: { contains: keyword } },
      ];
    }

    // 超管查询时额外 include 租户信息和统计数据
    const include: any = {
      roles: { include: { role: true } },
    };
    if (isSuperTenant) {
      include.tenant = {
        select: { id: true, name: true, code: true, tenantType: true, isSuper: true },
      };
      include._count = {
        select: { children: true, contestRegistrations: true },
      };
    }

    const [list, total] = await Promise.all([
      this.prisma.user.findMany({
        where,
        skip,
        take: pageSize,
        include,
        orderBy: { createTime: 'desc' },
      }),
      this.prisma.user.count({ where }),
    ]);

    return { list, total, page, pageSize };
  }

  /**
   * 用户类型统计（仅超管）
   */
  async getStats() {
    // 获取特殊租户 ID
    const specialTenants = await this.prisma.tenant.findMany({
      where: { validState: 1 },
      select: { id: true, code: true, isSuper: true, tenantType: true },
    });

    const superTenantIds = specialTenants.filter((t) => t.isSuper === 1).map((t) => t.id);
    const publicTenantIds = specialTenants.filter((t) => t.code === 'public').map((t) => t.id);
    const judgeTenantIds = specialTenants.filter((t) => t.code === 'judge').map((t) => t.id);
    const orgTenantIds = specialTenants
      .filter((t) => t.isSuper === 0 && t.code !== 'public' && t.code !== 'judge')
      .map((t) => t.id);

    const baseWhere = { validState: 1 };

    const [total, platform, org, judge, publicCount] = await Promise.all([
      this.prisma.user.count({ where: baseWhere }),
      this.prisma.user.count({ where: { ...baseWhere, tenantId: { in: superTenantIds } } }),
      this.prisma.user.count({ where: { ...baseWhere, tenantId: { in: orgTenantIds } } }),
      this.prisma.user.count({ where: { ...baseWhere, tenantId: { in: judgeTenantIds } } }),
      this.prisma.user.count({ where: { ...baseWhere, tenantId: { in: publicTenantIds } } }),
    ]);

    return { total, platform, org, judge, public: publicCount };
  }

  async findOne(id: number, tenantId?: number, isSuperTenant = false) {
    const where: any = { id };
    if (tenantId && !isSuperTenant) {
      where.tenantId = tenantId;
    }

    const user = await this.prisma.user.findFirst({
      where,
      include: {
        roles: {
          include: {
            role: {
              include: {
                permissions: { include: { permission: true } },
              },
            },
          },
        },
        tenant: {
          select: { id: true, name: true, code: true, tenantType: true, isSuper: true },
        },
        children: isSuperTenant
          ? { where: { isDeleted: 0 }, orderBy: { createTime: 'desc' } }
          : false,
        contestRegistrations: isSuperTenant
          ? {
              take: 20,
              orderBy: { createTime: 'desc' },
              include: {
                contest: { select: { id: true, contestName: true, contestState: true } },
                child: { select: { id: true, name: true } },
              },
            }
          : false,
        contestJudges: isSuperTenant
          ? {
              include: {
                contest: { select: { id: true, contestName: true, status: true } },
              },
            }
          : false,
      },
    });

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

    return user;
  }

  async findByUsername(username: string, tenantId?: number) {
    const where: any = { username };
    if (tenantId) {
      where.tenantId = tenantId;
    }

    return this.prisma.user.findFirst({
      where,
      include: {
        roles: {
          include: {
            role: {
              include: {
                permissions: {
                  include: {
                    permission: true,
                  },
                },
              },
            },
          },
        },
      },
    });
  }

  async update(id: number, updateUserDto: UpdateUserDto, tenantId?: number) {
    const { roleIds, ...userData } = updateUserDto;
    const data: any = { ...userData };

    // 验证用户是否存在且属于该租户
    const existingUser = await this.findOne(id, tenantId);

    if (updateUserDto.password) {
      data.password = await bcrypt.hash(updateUserDto.password, 10);
    }

    // 如果提供了 roleIds，更新角色关联
    if (roleIds !== undefined && tenantId) {
      // 验证角色是否属于该租户
      const roles = await this.prisma.role.findMany({
        where: {
          id: { in: roleIds },
          tenantId,
        },
      });
      if (roles.length !== roleIds.length) {
        throw new NotFoundException('部分角色不存在或不属于该租户');
      }

      // 先删除所有现有角色关联
      await this.prisma.userRole.deleteMany({
        where: { userId: id },
      });

      // 创建新的角色关联
      if (roleIds.length > 0) {
        data.roles = {
          create: roleIds.map((roleId) => ({
            roleId,
          })),
        };
      }
    }

    return this.prisma.user.update({
      where: { id },
      data,
      include: {
        roles: {
          include: {
            role: true,
          },
        },
      },
    });
  }

  /**
   * 切换用户状态（禁用/启用）
   */
  async updateStatus(
    id: number,
    status: 'enabled' | 'disabled',
    operatorId: number,
  ) {
    if (id === operatorId) {
      throw new BadRequestException('不能操作自己的账号');
    }

    const user = await this.prisma.user.findUnique({
      where: { id },
      include: { roles: { include: { role: true } } },
    });
    if (!user) {
      throw new NotFoundException('用户不存在');
    }

    // 禁用时检查是否是租户唯一管理员
    if (status === 'disabled') {
      const isAdmin = user.roles.some(
        (ur) => ur.role.code === 'tenant_admin' || ur.role.code === 'super_admin',
      );
      if (isAdmin) {
        const adminCount = await this.prisma.user.count({
          where: {
            tenantId: user.tenantId,
            status: 'enabled',
            validState: 1,
            roles: {
              some: {
                role: {
                  code: { in: ['tenant_admin', 'super_admin'] },
                },
              },
            },
          },
        });
        if (adminCount <= 1) {
          throw new BadRequestException('不能禁用租户唯一的管理员账号');
        }
      }
    }

    return this.prisma.user.update({
      where: { id },
      data: { status },
    });
  }

  async remove(id: number, tenantId?: number) {
    // 验证用户是否存在且属于该租户
    await this.findOne(id, tenantId);

    return this.prisma.user.delete({
      where: { id },
    });
  }

  /**
   * 根据 userType 构建租户查询条件
   */
  private buildTenantConditionByUserType(userType: string) {
    switch (userType) {
      case 'platform':
        return { isSuper: 1 };
      case 'public':
        return { code: 'public' };
      case 'judge':
        return { code: 'judge' };
      case 'org':
        return {
          isSuper: 0,
          code: { notIn: ['public', 'judge'] },
        };
      default:
        return null;
    }
  }
}
