import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { UsersService } from '../users/users.service';
import { CreateTenantDto } from './dto/create-tenant.dto';
import { UpdateFeatureToggleDto } from './dto/update-feature-toggle.dto';

@Injectable()
export class TenantsService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly usersService: UsersService,
  ) {}

  async create(dto: CreateTenantDto) {
    const plan = await this.prisma.plan.findUnique({ where: { id: dto.planId } });
    if (!plan) throw new BadRequestException('Plan not found');

    const existing = await this.prisma.user.findUnique({ where: { email: dto.adminEmail } });
    if (existing) throw new BadRequestException('Admin email already used');

    const tenant = await this.prisma.tenant.create({
      data: {
        companyName: dto.companyName,
        legalId: dto.legalId,
        contactEmail: dto.contactEmail,
        contactPhone: dto.contactPhone,
        city: dto.city,
        country: dto.country ?? 'MA',
        planId: plan.id,
        status: 'TRIAL',
        trialEndsAt: new Date(Date.now() + 30 * 24 * 3600 * 1000),
        featureToggles: {
          create: [
            { featureKey: 'finance', enabled: true, activatedAt: new Date() },
            { featureKey: 'ticketing', enabled: false },
            { featureKey: 'evoting', enabled: false },
            { featureKey: 'qr_access', enabled: false },
          ],
        },
      },
      include: { plan: true, featureToggles: true },
    });

    const admin = await this.usersService.createWithRole({
      email: dto.adminEmail,
      password: dto.adminPassword,
      firstName: dto.adminFirstName,
      lastName: dto.adminLastName,
      roleCode: 'SYNDIC',
      tenantId: tenant.id,
    });

    return { tenant, admin: { id: admin.id, email: admin.email } };
  }

  findAll() {
    return this.prisma.tenant.findMany({
      include: { plan: true, _count: { select: { complexes: true } } },
      orderBy: { createdAt: 'desc' },
    });
  }

  async findOne(id: string) {
    const tenant = await this.prisma.tenant.findUnique({
      where: { id },
      include: {
        plan: true,
        featureToggles: true,
        _count: { select: { complexes: true, userRoles: true } },
      },
    });
    if (!tenant) throw new NotFoundException();
    return tenant;
  }

  async updateFeatureToggle(tenantId: string, dto: UpdateFeatureToggleDto) {
    return this.prisma.tenantFeatureToggle.upsert({
      where: { tenantId_featureKey: { tenantId, featureKey: dto.featureKey } },
      create: {
        tenantId,
        featureKey: dto.featureKey,
        enabled: dto.enabled,
        activatedAt: dto.enabled ? new Date() : null,
      },
      update: {
        enabled: dto.enabled,
        activatedAt: dto.enabled ? new Date() : null,
      },
    });
  }

  async suspend(id: string) {
    return this.prisma.tenant.update({ where: { id }, data: { status: 'SUSPENDED' } });
  }

  async activate(id: string) {
    return this.prisma.tenant.update({ where: { id }, data: { status: 'ACTIVE' } });
  }

  // SaaS billing: (fixedPrice) + (pricePerLot × totalLots)
  async generateInvoice(tenantId: string) {
    const tenant = await this.prisma.tenant.findUnique({
      where: { id: tenantId },
      include: { plan: true, complexes: { include: { _count: { select: { spatialUnits: true } } } } },
    });
    if (!tenant) throw new NotFoundException();

    const lotsCount = await this.prisma.lot.count({
      where: { spatialUnit: { complex: { tenantId } } },
    });

    const amount =
      Number(tenant.plan.fixedPrice) + Number(tenant.plan.pricePerLot) * lotsCount;

    const now = new Date();
    const periodStart = new Date(now.getFullYear(), now.getMonth(), 1);
    const periodEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0);
    const dueDate = new Date(now.getFullYear(), now.getMonth() + 1, 15);

    return this.prisma.saasInvoice.create({
      data: {
        tenantId,
        amount,
        currency: tenant.plan.currency,
        periodStart,
        periodEnd,
        lotsCount,
        dueDate,
      },
    });
  }
}
