import {
  Injectable,
  NotFoundException,
  ConflictException,
  BadRequestException,
} from '@nestjs/common';
import { PrismaService } from '../../database/prisma.service';
import * as bcrypt from 'bcrypt';
import {
  TenantQueryDto,
  CreateTenantDto,
  UpdateTenantDto,
  UpdateTenantQuotaDto,
  UpdateTenantStatusDto,
} from './dto/tenant.dto';

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

  async findAllPaginated(query: TenantQueryDto) {
    const { page = 1, pageSize = 10, keyword, status, packageType } = query;
    const skip = (page - 1) * pageSize;

    const where: any = {};

    if (keyword) {
      where.OR = [
        { name: { contains: keyword } },
        { loginAccount: { contains: keyword } },
        { contactPerson: { contains: keyword } },
        { contactPhone: { contains: keyword } },
      ];
    }

    if (status) {
      where.status = status;
    }

    if (packageType) {
      where.packageType = packageType;
    }

    const [items, total] = await Promise.all([
      this.prisma.tenant.findMany({
        where,
        select: {
          id: true,
          name: true,
          loginAccount: true,
          address: true,
          contactPerson: true,
          contactPhone: true,
          packageType: true,
          teacherQuota: true,
          studentQuota: true,
          teacherCount: true,
          studentCount: true,
          startDate: true,
          expireDate: true,
          status: true,
          createdAt: true,
        },
        orderBy: { createdAt: 'desc' },
        skip,
        take: pageSize,
      }),
      this.prisma.tenant.count({ where }),
    ]);

    return {
      items,
      total,
      page,
      pageSize,
      totalPages: Math.ceil(total / pageSize),
    };
  }

  async findAll() {
    return this.prisma.tenant.findMany({
      select: {
        id: true,
        name: true,
        address: true,
        contactPerson: true,
        contactPhone: true,
        packageType: true,
        teacherQuota: true,
        studentQuota: true,
        teacherCount: true,
        studentCount: true,
        startDate: true,
        expireDate: true,
        status: true,
        createdAt: true,
      },
      orderBy: { createdAt: 'desc' },
    });
  }

  async findOne(id: number) {
    const tenant = await this.prisma.tenant.findUnique({
      where: { id },
      select: {
        id: true,
        name: true,
        loginAccount: true,
        address: true,
        contactPerson: true,
        contactPhone: true,
        logoUrl: true,
        packageType: true,
        teacherQuota: true,
        studentQuota: true,
        storageQuota: true,
        teacherCount: true,
        studentCount: true,
        storageUsed: true,
        startDate: true,
        expireDate: true,
        status: true,
        createdAt: true,
        updatedAt: true,
        teachers: {
          select: {
            id: true,
            name: true,
            phone: true,
            email: true,
            status: true,
            lessonCount: true,
          },
          take: 10,
          orderBy: { createdAt: 'desc' },
        },
        students: {
          select: {
            id: true,
            name: true,
            classId: true,
            gender: true,
            readingCount: true,
          },
          take: 10,
          orderBy: { createdAt: 'desc' },
        },
        classes: {
          select: {
            id: true,
            name: true,
            grade: true,
            studentCount: true,
          },
          take: 10,
        },
        _count: {
          select: {
            teachers: true,
            students: true,
            classes: true,
            lessons: true,
          },
        },
      },
    });

    if (!tenant) {
      throw new NotFoundException(`租户 #${id} 不存在`);
    }

    // Convert BigInt to string for JSON serialization
    return {
      ...tenant,
      storageQuota: tenant.storageQuota?.toString() || '0',
      storageUsed: tenant.storageUsed?.toString() || '0',
    };
  }

  async create(dto: CreateTenantDto) {
    // Check if login account already exists
    const existing = await this.prisma.tenant.findUnique({
      where: { loginAccount: dto.loginAccount },
    });

    if (existing) {
      throw new ConflictException('登录账号已存在');
    }

    // Check if teacher login account exists too
    const existingTeacher = await this.prisma.teacher.findUnique({
      where: { loginAccount: dto.loginAccount },
    });

    if (existingTeacher) {
      throw new ConflictException('该账号已被教师使用');
    }

    // Hash password
    const defaultPassword = dto.password || '123456';
    const passwordHash = await bcrypt.hash(defaultPassword, 10);

    // Set default dates if not provided
    const startDate = dto.startDate || new Date().toISOString().split('T')[0];
    const expireDate =
      dto.expireDate ||
      new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];

    const tenant = await this.prisma.tenant.create({
      data: {
        name: dto.name,
        loginAccount: dto.loginAccount,
        passwordHash,
        address: dto.address,
        contactPerson: dto.contactPerson,
        contactPhone: dto.contactPhone,
        packageType: dto.packageType || 'STANDARD',
        teacherQuota: dto.teacherQuota || 20,
        studentQuota: dto.studentQuota || 200,
        startDate,
        expireDate,
        status: 'ACTIVE',
      },
      select: {
        id: true,
        name: true,
        loginAccount: true,
        address: true,
        contactPerson: true,
        contactPhone: true,
        packageType: true,
        teacherQuota: true,
        studentQuota: true,
        startDate: true,
        expireDate: true,
        status: true,
        createdAt: true,
      },
    });

    return {
      ...tenant,
      tempPassword: dto.password || '123456',
    };
  }

  async update(id: number, dto: UpdateTenantDto) {
    // Check if tenant exists
    const existing = await this.prisma.tenant.findUnique({
      where: { id },
    });

    if (!existing) {
      throw new NotFoundException(`租户 #${id} 不存在`);
    }

    return this.prisma.tenant.update({
      where: { id },
      data: {
        name: dto.name,
        address: dto.address,
        contactPerson: dto.contactPerson,
        contactPhone: dto.contactPhone,
        packageType: dto.packageType,
        teacherQuota: dto.teacherQuota,
        studentQuota: dto.studentQuota,
        startDate: dto.startDate,
        expireDate: dto.expireDate,
        status: dto.status,
      },
      select: {
        id: true,
        name: true,
        loginAccount: true,
        address: true,
        contactPerson: true,
        contactPhone: true,
        packageType: true,
        teacherQuota: true,
        studentQuota: true,
        startDate: true,
        expireDate: true,
        status: true,
        createdAt: true,
        updatedAt: true,
      },
    });
  }

  async updateQuota(id: number, dto: UpdateTenantQuotaDto) {
    // Check if tenant exists
    const existing = await this.prisma.tenant.findUnique({
      where: { id },
    });

    if (!existing) {
      throw new NotFoundException(`租户 #${id} 不存在`);
    }

    // Validate quota not less than current usage
    if (dto.teacherQuota !== undefined && dto.teacherQuota < existing.teacherCount) {
      throw new BadRequestException(
        `教师配额不能小于当前已用数量 (${existing.teacherCount})`,
      );
    }

    if (dto.studentQuota !== undefined && dto.studentQuota < existing.studentCount) {
      throw new BadRequestException(
        `学生配额不能小于当前已用数量 (${existing.studentCount})`,
      );
    }

    return this.prisma.tenant.update({
      where: { id },
      data: {
        packageType: dto.packageType,
        teacherQuota: dto.teacherQuota,
        studentQuota: dto.studentQuota,
      },
      select: {
        id: true,
        name: true,
        packageType: true,
        teacherQuota: true,
        studentQuota: true,
        teacherCount: true,
        studentCount: true,
      },
    });
  }

  async updateStatus(id: number, dto: UpdateTenantStatusDto) {
    // Check if tenant exists
    const existing = await this.prisma.tenant.findUnique({
      where: { id },
    });

    if (!existing) {
      throw new NotFoundException(`租户 #${id} 不存在`);
    }

    return this.prisma.tenant.update({
      where: { id },
      data: {
        status: dto.status,
      },
      select: {
        id: true,
        name: true,
        status: true,
      },
    });
  }

  async resetPassword(id: number) {
    // Check if tenant exists
    const existing = await this.prisma.tenant.findUnique({
      where: { id },
    });

    if (!existing) {
      throw new NotFoundException(`租户 #${id} 不存在`);
    }

    // Generate random password
    const tempPassword = Math.random().toString(36).slice(-8);
    const passwordHash = await bcrypt.hash(tempPassword, 10);

    await this.prisma.tenant.update({
      where: { id },
      data: {
        passwordHash,
      },
    });

    return {
      tempPassword,
    };
  }

  async remove(id: number) {
    // Check if tenant exists
    const existing = await this.prisma.tenant.findUnique({
      where: { id },
    });

    if (!existing) {
      throw new NotFoundException(`租户 #${id} 不存在`);
    }

    await this.prisma.tenant.delete({
      where: { id },
    });

    return { success: true };
  }

  async getStats() {
    const [totalCount, activeCount, expiredCount] = await Promise.all([
      this.prisma.tenant.count(),
      this.prisma.tenant.count({ where: { status: 'ACTIVE' } }),
      this.prisma.tenant.count({ where: { status: { not: 'ACTIVE' } } }),
    ]);

    const packageDistribution = await this.prisma.tenant.groupBy({
      by: ['packageType'],
      _count: {
        id: true,
      },
    });

    return {
      totalCount,
      activeCount,
      expiredCount,
      packageDistribution: packageDistribution.map((item) => ({
        packageType: item.packageType,
        count: item._count.id,
      })),
    };
  }
}
