// ============================================================
// SAAS MODULE — Klavo
// Emissão de licenças, API keys e medição de uso de sistemas integrados
// ============================================================
import { Module, Injectable, NotFoundException,
  ForbiddenException, UnauthorizedException, ConflictException,
  Logger, NestMiddleware } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, DataSource } from 'typeorm';
import {
  Entity, PrimaryGeneratedColumn, Column, CreateDateColumn,
  UpdateDateColumn, ManyToOne, JoinColumn,
} from 'typeorm';
import {
  Controller, Get, Post, Put, Patch, Delete,
  Body, Param, Query, UseGuards, Request,
  HttpCode, HttpStatus, Req, Res, Next,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiHeader } from '@nestjs/swagger';
import {
  IsString, IsOptional, IsUUID, IsArray, IsNumber,
  IsIn, IsDateString, IsBoolean, Min, MinLength,
} from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import * as bcrypt from 'bcrypt';
import { v4 as uuidv4 } from 'uuid';
import { IsEmail } from 'class-validator';
import { Tenant, User, UserTenantMembership } from '../auth/auth.module';

// ============================================================
// ENTITIES
// ============================================================
@Entity('saas_plans')
export class SaasPlan {
  @PrimaryGeneratedColumn('uuid') id: string;
  @Column({ length: 80, unique: true }) name: string;
  @Column({ type: 'text', nullable: true }) description: string;
  @Column({ name: 'price_monthly', type: 'numeric', precision: 15, scale: 2, default: 0 }) priceMonthly: number;
  @Column({ name: 'price_yearly', type: 'numeric', precision: 15, scale: 2, nullable: true }) priceYearly: number;
  @Column({ name: 'max_api_calls', type: 'bigint', default: -1 }) maxApiCalls: number;
  @Column({ name: 'max_licenses', default: -1 }) maxLicenses: number;
  @Column({ name: 'max_endpoints', default: -1 }) maxEndpoints: number;
  @Column({ name: 'modules_included', type: 'text', array: true, default: '{}' }) modulesIncluded: string[];
  @Column({ name: 'is_active', default: true }) isActive: boolean;
  @CreateDateColumn({ name: 'created_at' }) createdAt: Date;
  @UpdateDateColumn({ name: 'updated_at' }) updatedAt: Date;
}

@Entity('saas_licenses')
export class SaasLicense {
  @PrimaryGeneratedColumn('uuid') id: string;
  @Column({ name: 'tenant_id' }) tenantId: string;
  @Column({ name: 'client_id' }) clientId: string;
  @Column({ name: 'product_id' }) productId: string;
  @Column({ name: 'created_by', nullable: true }) createdBy: string;
  @Column({ name: 'license_key', length: 64, unique: true }) licenseKey: string;
  @Column({ name: 'license_name', length: 150 }) licenseName: string;
  @Column({ type: 'text', nullable: true }) description: string;
  @Column({ name: 'starts_at', type: 'timestamptz', default: () => 'NOW()' }) startsAt: Date;
  @Column({ name: 'expires_at', type: 'timestamptz', nullable: true }) expiresAt: Date;
  @Column({ name: 'max_api_calls', type: 'bigint', default: -1 }) maxApiCalls: number;
  @Column({ name: 'max_endpoints', default: -1 }) maxEndpoints: number;
  @Column({ name: 'contract_id', nullable: true }) contractId: string;
  @Column({ name: 'billing_metric', default: 'fixed' }) billingMetric: string;
  @Column({ name: 'unit_price', type: 'numeric', precision: 15, scale: 2, default: 0 }) unitPrice: number;
  @Column({ default: 'active' }) status: string;
  @Column({ name: 'suspended_at', type: 'timestamptz', nullable: true }) suspendedAt: Date;
  @Column({ name: 'revoked_at', type: 'timestamptz', nullable: true }) revokedAt: Date;
  @Column({ name: 'revoke_reason', nullable: true }) revokeReason: string;
  @Column({ name: 'last_used_at', type: 'timestamptz', nullable: true }) lastUsedAt: Date;
  @Column({ name: 'provisioned_tenant_id', nullable: true }) provisionedTenantId: string;

  @CreateDateColumn({ name: 'created_at' }) createdAt: Date;
  @UpdateDateColumn({ name: 'updated_at' }) updatedAt: Date;
}

@Entity('saas_api_keys')
export class SaasApiKey {
  @PrimaryGeneratedColumn('uuid') id: string;
  @Column({ name: 'license_id' }) licenseId: string;
  @Column({ name: 'tenant_id' }) tenantId: string;
  @Column({ length: 80 }) name: string;
  @Column({ name: 'key_hash' }) keyHash: string;
  @Column({ name: 'key_prefix', length: 12 }) keyPrefix: string;
  @Column({ default: 'production' }) environment: string;
  @Column({ name: 'allowed_ips', type: 'text', array: true, nullable: true }) allowedIps: string[];
  @Column({ name: 'rate_limit_rpm', default: 60 }) rateLimitRpm: number;
  @Column({ default: 'active' }) status: string;
  @Column({ name: 'revoked_at', type: 'timestamptz', nullable: true }) revokedAt: Date;
  @Column({ name: 'last_used_at', type: 'timestamptz', nullable: true }) lastUsedAt: Date;
  @Column({ name: 'last_used_ip', nullable: true }) lastUsedIp: string;

  @ManyToOne(() => SaasLicense, { onDelete: 'CASCADE' })
  @JoinColumn({ name: 'license_id' })
  license: SaasLicense;

  @CreateDateColumn({ name: 'created_at' }) createdAt: Date;
}

@Entity('saas_endpoints')
export class SaasEndpoint {
  @PrimaryGeneratedColumn('uuid') id: string;
  @Column({ name: 'license_id' }) licenseId: string;
  @Column({ name: 'tenant_id' }) tenantId: string;
  @Column({ length: 200 }) path: string;
  @Column({ default: 'ANY' }) method: string;
  @Column({ type: 'text', nullable: true }) description: string;
  @Column({ name: 'is_active', default: true }) isActive: boolean;
  @CreateDateColumn({ name: 'created_at' }) createdAt: Date;
}

@Entity('saas_usage_events')
export class SaasUsageEvent {
  @PrimaryGeneratedColumn('uuid') id: string;
  @Column({ name: 'tenant_id' }) tenantId: string;
  @Column({ name: 'license_id' }) licenseId: string;
  @Column({ name: 'api_key_id', nullable: true }) apiKeyId: string;
  @Column({ nullable: true }) endpoint: string;
  @Column({ name: 'http_method', nullable: true }) httpMethod: string;
  @Column({ name: 'http_status', type: 'smallint', nullable: true }) httpStatus: number;
  @Column({ name: 'response_ms', nullable: true }) responseMs: number;
  @Column({ name: 'payload_bytes', nullable: true }) payloadBytes: number;
  @Column({ name: 'client_ip', nullable: true }) clientIp: string;
  @Column({ name: 'user_agent', type: 'text', nullable: true }) userAgent: string;
  @Column({ name: 'billing_period', length: 7 }) billingPeriod: string;
  @Column({ name: 'occurred_at', type: 'timestamptz', default: () => 'NOW()' }) occurredAt: Date;
}

@Entity('saas_usage_summaries')
export class SaasUsageSummary {
  @PrimaryGeneratedColumn('uuid') id: string;
  @Column({ name: 'tenant_id' }) tenantId: string;
  @Column({ name: 'license_id' }) licenseId: string;
  @Column({ name: 'billing_period', length: 7 }) billingPeriod: string;
  @Column({ name: 'total_calls', type: 'bigint', default: 0 }) totalCalls: number;
  @Column({ name: 'success_calls', type: 'bigint', default: 0 }) successCalls: number;
  @Column({ name: 'error_calls', type: 'bigint', default: 0 }) errorCalls: number;
  @Column({ name: 'avg_response_ms', nullable: true }) avgResponseMs: number;
  @Column({ name: 'total_bytes', type: 'bigint', default: 0 }) totalBytes: number;
  @Column({ name: 'billable_units', type: 'numeric', precision: 15, scale: 4, default: 0 }) billableUnits: number;
  @Column({ name: 'unit_price', type: 'numeric', precision: 15, scale: 2, default: 0 }) unitPrice: number;
  @Column({ name: 'amount_due', type: 'numeric', precision: 15, scale: 2, default: 0 }) amountDue: number;
  @Column({ default: false }) billed: boolean;
  @Column({ name: 'charge_id', nullable: true }) chargeId: string;
  @Column({ name: 'closed_at', type: 'timestamptz', nullable: true }) closedAt: Date;
  @CreateDateColumn({ name: 'created_at' }) createdAt: Date;
  @UpdateDateColumn({ name: 'updated_at' }) updatedAt: Date;
}

// ============================================================
// DTOs
// ============================================================
export class CreateLicenseDto {
  @ApiProperty() @IsUUID() clientId: string;
  @ApiProperty({ description: 'ID do produto (plano)' }) @IsUUID() productId: string;
  @ApiProperty({ example: 'Klavo — Empresa XPTO' }) @IsString() @MinLength(2) licenseName: string;
  @ApiPropertyOptional() @IsOptional() @IsString() description?: string;
  @ApiPropertyOptional() @IsOptional() @IsDateString() expiresAt?: string;
  @ApiPropertyOptional({ default: -1 }) @IsOptional() @IsNumber() maxApiCalls?: number;
  @ApiPropertyOptional({ default: -1 }) @IsOptional() @IsNumber() maxEndpoints?: number;
  @ApiPropertyOptional() @IsOptional() @IsUUID() contractId?: string;
  @ApiPropertyOptional({ enum: ['fixed','per_call','per_endpoint'], default: 'fixed' })
  @IsOptional() @IsIn(['fixed','per_call','per_endpoint']) billingMetric?: string;
  @ApiPropertyOptional({ default: 0 }) @IsOptional() @IsNumber() @Min(0) unitPrice?: number;

  // Provisionamento do tenant (empresa que vai usar o Klavo)
  @ApiProperty({ description: 'Razão social da empresa licenciada' }) @IsString() @MinLength(2) companyName: string;
  @ApiProperty({ description: 'CNPJ da empresa (14 dígitos)' }) @IsString() @MinLength(14) companyDocument: string;
  @ApiProperty({ description: 'E-mail corporativo da empresa' }) @IsEmail() companyEmail: string;
  @ApiProperty({ description: 'Nome do operador / responsável' }) @IsString() @MinLength(2) operatorName: string;
  @ApiProperty({ description: 'E-mail de acesso do operador' }) @IsEmail() operatorEmail: string;
  @ApiProperty({ description: 'Senha inicial (mín. 8 chars)' }) @IsString() @MinLength(8) operatorPassword: string;
}

export class CreateApiKeyDto {
  @ApiProperty({ example: 'Produção' }) @IsString() @MinLength(2) name: string;
  @ApiPropertyOptional({ enum: ['production','sandbox'], default: 'production' })
  @IsOptional() @IsIn(['production','sandbox']) environment?: string;
  @ApiPropertyOptional({ description: 'IPs permitidos (null = qualquer)', type: [String] })
  @IsOptional() @IsArray() allowedIps?: string[];
  @ApiPropertyOptional({ default: 60 }) @IsOptional() @IsNumber() @Min(1) rateLimitRpm?: number;
}

export class AddEndpointDto {
  @ApiProperty({ example: '/api/v1/contracts' }) @IsString() path: string;
  @ApiPropertyOptional({ enum: ['GET','POST','PUT','PATCH','DELETE','ANY'], default: 'ANY' })
  @IsOptional() @IsIn(['GET','POST','PUT','PATCH','DELETE','ANY']) method?: string;
  @ApiPropertyOptional() @IsOptional() @IsString() description?: string;
}

export class RevokeReasonDto {
  @ApiProperty() @IsString() @MinLength(5) reason: string;
}

// ============================================================
// SERVICE: SaasService
// ============================================================
@Injectable()
export class SaasService {
  private readonly logger = new Logger(SaasService.name);

  constructor(
    @InjectRepository(SaasLicense)
    private readonly licenseRepo: Repository<SaasLicense>,

    @InjectRepository(SaasApiKey)
    private readonly apiKeyRepo: Repository<SaasApiKey>,

    @InjectRepository(SaasEndpoint)
    private readonly endpointRepo: Repository<SaasEndpoint>,

    @InjectRepository(SaasUsageEvent)
    private readonly usageEventRepo: Repository<SaasUsageEvent>,

    @InjectRepository(SaasUsageSummary)
    private readonly summaryRepo: Repository<SaasUsageSummary>,

    @InjectRepository(Tenant)
    private readonly tenantRepo: Repository<Tenant>,

    @InjectRepository(User)
    private readonly userRepo: Repository<User>,

    @InjectRepository(UserTenantMembership)
    private readonly membershipRepo: Repository<UserTenantMembership>,

  ) {}

  // ----------------------------------------------------------
  // Licenças
  // ----------------------------------------------------------
  async createLicense(tenantId: string, userId: string, dto: CreateLicenseDto): Promise<SaasLicense & { provisionedEmail: string }> {
    // Verificar se o CNPJ da empresa já está cadastrado
    const existing = await this.tenantRepo.findOneBy({ document: dto.companyDocument.replace(/\D/g, '') });
    if (existing) throw new ConflictException('CNPJ já possui uma conta na plataforma');

    // 1. Provisionar tenant (empresa licenciada)
    const newTenant = await this.tenantRepo.save(
      this.tenantRepo.create({
        name: dto.companyName,
        document: dto.companyDocument.replace(/\D/g, ''),
        email: dto.companyEmail,
      }),
    );

    // 2. Criar usuário operador
    const passwordHash = await bcrypt.hash(dto.operatorPassword, 10);
    const operator = await this.userRepo.save(
      this.userRepo.create({
        tenantId: newTenant.id,
        name: dto.operatorName,
        email: dto.operatorEmail,
        passwordHash,
        isOwner: true,
      }),
    );

    // 3. Criar membership owner
    await this.membershipRepo.save(
      this.membershipRepo.create({
        email: operator.email,
        tenantId: newTenant.id,
        role: 'owner',
      }),
    );

    // 4. Registrar a licença vinculando ao tenant provisionado
    const licenseKey = `kl_${uuidv4().replace(/-/g, '')}`;
    const license = await this.licenseRepo.save(
      this.licenseRepo.create({
        tenantId,
        clientId: dto.clientId,
        productId: dto.productId,
        createdBy: userId,
        licenseKey,
        licenseName: dto.licenseName,
        description: dto.description,
        expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : null,
        maxApiCalls: dto.maxApiCalls ?? -1,
        maxEndpoints: dto.maxEndpoints ?? -1,
        contractId: dto.contractId,
        billingMetric: dto.billingMetric ?? 'fixed',
        unitPrice: dto.unitPrice ?? 0,
        status: 'active',
        provisionedTenantId: newTenant.id,
      }),
    );

    return { ...license, provisionedEmail: operator.email };
  }

  async listLicenses(tenantId: string, status?: string): Promise<SaasLicense[]> {
    const where: any = { tenantId };
    if (status) where.status = status;
    return this.licenseRepo.find({ where, order: { createdAt: 'DESC' } });
  }

  async findLicense(tenantId: string, id: string): Promise<SaasLicense> {
    const lic = await this.licenseRepo.findOne({ where: { id, tenantId } });
    if (!lic) throw new NotFoundException('Licença não encontrada');
    return lic;
  }

  async suspendLicense(tenantId: string, id: string): Promise<SaasLicense> {
    const lic = await this.findLicense(tenantId, id);
    lic.status = 'suspended';
    lic.suspendedAt = new Date();
    return this.licenseRepo.save(lic);
  }

  async revokeLicense(tenantId: string, id: string, dto: RevokeReasonDto): Promise<SaasLicense> {
    const lic = await this.findLicense(tenantId, id);
    lic.status = 'revoked';
    lic.revokedAt = new Date();
    lic.revokeReason = dto.reason;
    return this.licenseRepo.save(lic);
  }

  async reactivateLicense(tenantId: string, id: string): Promise<SaasLicense> {
    const lic = await this.findLicense(tenantId, id);
    if (lic.status === 'revoked') throw new ForbiddenException('Licenças revogadas não podem ser reativadas');
    lic.status = 'active';
    lic.suspendedAt = null;
    return this.licenseRepo.save(lic);
  }

  // ----------------------------------------------------------
  // API Keys
  // ----------------------------------------------------------
  async createApiKey(
    tenantId: string,
    licenseId: string,
    dto: CreateApiKeyDto,
  ): Promise<{ apiKey: SaasApiKey; plainKey: string }> {
    const license = await this.findLicense(tenantId, licenseId);
    if (license.status !== 'active') throw new ForbiddenException('Licença inativa');

    // Gera a key no formato: kl_live_XXXXXXXXXXXXXXXX
    const env = dto.environment === 'sandbox' ? 'test' : 'live';
    const rawKey = `kl_${env}_${uuidv4().replace(/-/g, '').substring(0, 24)}`;
    const prefix = rawKey.substring(0, 12);
    const keyHash = await bcrypt.hash(rawKey, 10);

    const apiKey = this.apiKeyRepo.create({
      tenantId,
      licenseId,
      name: dto.name,
      keyHash,
      keyPrefix: prefix,
      environment: dto.environment ?? 'production',
      allowedIps: dto.allowedIps ?? null,
      rateLimitRpm: dto.rateLimitRpm ?? 60,
      status: 'active',
    });

    const saved = await this.apiKeyRepo.save(apiKey);
    this.logger.log(`API Key criada: ${prefix}*** [licença ${licenseId}]`);

    // Retorna a key em plain text APENAS neste momento — nunca mais recuperável
    return { apiKey: saved, plainKey: rawKey };
  }

  async listApiKeys(tenantId: string, licenseId: string): Promise<SaasApiKey[]> {
    await this.findLicense(tenantId, licenseId);
    return this.apiKeyRepo.find({ where: { tenantId, licenseId }, order: { createdAt: 'DESC' } });
  }

  async revokeApiKey(tenantId: string, licenseId: string, keyId: string): Promise<SaasApiKey> {
    const key = await this.apiKeyRepo.findOne({ where: { id: keyId, tenantId, licenseId } });
    if (!key) throw new NotFoundException('API Key não encontrada');
    key.status = 'revoked';
    key.revokedAt = new Date();
    return this.apiKeyRepo.save(key);
  }

  // ----------------------------------------------------------
  // Validar API Key (usada pelo middleware de integração)
  // ----------------------------------------------------------
  async validateApiKey(rawKey: string): Promise<{ apiKey: SaasApiKey; license: SaasLicense } | null> {
    if (!rawKey?.startsWith('kl_')) return null;
    const prefix = rawKey.substring(0, 12);

    const candidates = await this.apiKeyRepo.find({
      where: { keyPrefix: prefix, status: 'active' },
      relations: ['license', 'license.plan'],
    });

    for (const candidate of candidates) {
      const match = await bcrypt.compare(rawKey, candidate.keyHash);
      if (!match) continue;

      const license = candidate.license;
      if (!license || license.status !== 'active') continue;
      if (license.expiresAt && license.expiresAt < new Date()) {
        license.status = 'expired';
        await this.licenseRepo.save(license);
        continue;
      }

      return { apiKey: candidate, license };
    }

    return null;
  }

  // ----------------------------------------------------------
  // Endpoints
  // ----------------------------------------------------------
  async addEndpoint(tenantId: string, licenseId: string, dto: AddEndpointDto): Promise<SaasEndpoint> {
    await this.findLicense(tenantId, licenseId);
    return this.endpointRepo.save(
      this.endpointRepo.create({ tenantId, licenseId, ...dto, method: dto.method ?? 'ANY' }),
    );
  }

  async listEndpoints(tenantId: string, licenseId: string): Promise<SaasEndpoint[]> {
    return this.endpointRepo.find({ where: { tenantId, licenseId } });
  }

  async removeEndpoint(tenantId: string, licenseId: string, endpointId: string): Promise<void> {
    const ep = await this.endpointRepo.findOne({ where: { id: endpointId, tenantId, licenseId } });
    if (!ep) throw new NotFoundException('Endpoint não encontrado');
    await this.endpointRepo.remove(ep);
  }

  // ----------------------------------------------------------
  // Registrar evento de uso (inline — sem fila)
  // ----------------------------------------------------------
  async recordUsage(params: {
    tenantId: string;
    licenseId: string;
    apiKeyId: string;
    endpoint: string;
    httpMethod: string;
    httpStatus: number;
    responseMs: number;
    payloadBytes: number;
    clientIp: string;
    userAgent: string;
  }): Promise<void> {
    const period = new Date().toISOString().substring(0, 7); // YYYY-MM
    try {
      const event = this.usageEventRepo.create({ ...params, billingPeriod: period });
      await this.usageEventRepo.save(event);
    } catch (err) {
      this.logger.error('Falha ao gravar evento de uso', err.message);
    }
  }

  // ----------------------------------------------------------
  // Métricas e dashboard de uso
  // ----------------------------------------------------------
  async getUsageSummary(tenantId: string, licenseId: string, period?: string): Promise<SaasUsageSummary[]> {
    await this.findLicense(tenantId, licenseId);
    const qb = this.summaryRepo.createQueryBuilder('s')
      .where('s.tenant_id = :tenantId', { tenantId })
      .andWhere('s.license_id = :licenseId', { licenseId })
      .orderBy('s.billing_period', 'DESC');
    if (period) qb.andWhere('s.billing_period = :period', { period });
    return qb.limit(12).getMany();
  }

  async getLicenseDashboard(tenantId: string, licenseId: string): Promise<{
    license: SaasLicense;
    currentPeriod: string;
    callsThisPeriod: number;
    callsLimit: number;
    usagePercent: number;
    recentEvents: SaasUsageEvent[];
  }> {
    const license = await this.findLicense(tenantId, licenseId);
    const currentPeriod = new Date().toISOString().substring(0, 7);

    const [{ count }] = await this.usageEventRepo.query(
      `SELECT COUNT(*) as count FROM saas_usage_events
       WHERE license_id = $1 AND billing_period = $2`,
      [licenseId, currentPeriod],
    );

    const callsThisPeriod = Number(count);
    const callsLimit = license.maxApiCalls === -1 ? Infinity : Number(license.maxApiCalls);
    const usagePercent = callsLimit === Infinity ? 0 : Math.round((callsThisPeriod / callsLimit) * 100);

    const recentEvents = await this.usageEventRepo.find({
      where: { licenseId, tenantId },
      order: { occurredAt: 'DESC' },
      take: 20,
    });

    return { license, currentPeriod, callsThisPeriod, callsLimit, usagePercent, recentEvents };
  }

  // ----------------------------------------------------------
  // Fechamento de período e geração de cobrança (cron mensal)
  // ----------------------------------------------------------
  async closeBillingPeriod(tenantId: string, licenseId: string, period: string): Promise<SaasUsageSummary> {
    const license = await this.findLicense(tenantId, licenseId);

    const [stats] = await this.usageEventRepo.query(
      `SELECT
         COUNT(*) as total_calls,
         COUNT(*) FILTER (WHERE http_status < 400) as success_calls,
         COUNT(*) FILTER (WHERE http_status >= 400) as error_calls,
         AVG(response_ms)::INTEGER as avg_response_ms,
         COALESCE(SUM(payload_bytes), 0) as total_bytes
       FROM saas_usage_events
       WHERE license_id = $1 AND billing_period = $2`,
      [licenseId, period],
    );

    const totalCalls = Number(stats.total_calls);
    let billableUnits = 0;
    let amountDue = 0;

    if (license.billingMetric === 'per_call') {
      billableUnits = totalCalls;
      amountDue = +(billableUnits * Number(license.unitPrice)).toFixed(2);
    }

    const summary = this.summaryRepo.create({
      tenantId,
      licenseId,
      billingPeriod: period,
      totalCalls,
      successCalls: Number(stats.success_calls),
      errorCalls: Number(stats.error_calls),
      avgResponseMs: stats.avg_response_ms,
      totalBytes: Number(stats.total_bytes),
      billableUnits,
      unitPrice: Number(license.unitPrice),
      amountDue,
      closedAt: new Date(),
    });

    return this.summaryRepo.save(summary);
  }
}

// ============================================================
// CONTROLLERS
// ============================================================
@ApiTags('Gestão SaaS — Licenças')
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'))
@Controller('saas/licenses')
export class SaasLicensesController {
  constructor(private readonly saasService: SaasService) {}

  @Post()
  @ApiOperation({ summary: 'Emitir nova licença para um cliente' })
  create(@Body() dto: CreateLicenseDto, @Request() req: any) {
    return this.saasService.createLicense(req.user.tenantId, req.user.userId, dto);
  }

  @Get()
  @ApiOperation({ summary: 'Listar licenças emitidas' })
  list(@Request() req: any, @Query('status') status?: string) {
    return this.saasService.listLicenses(req.user.tenantId, status);
  }

  @Get(':id')
  @ApiOperation({ summary: 'Detalhar licença' })
  findOne(@Param('id') id: string, @Request() req: any) {
    return this.saasService.findLicense(req.user.tenantId, id);
  }

  @Get(':id/dashboard')
  @ApiOperation({ summary: 'Dashboard de uso da licença no período atual' })
  dashboard(@Param('id') id: string, @Request() req: any) {
    return this.saasService.getLicenseDashboard(req.user.tenantId, id);
  }

  @Get(':id/usage')
  @ApiOperation({ summary: 'Histórico de uso mensal da licença' })
  usage(@Param('id') id: string, @Request() req: any, @Query('period') period?: string) {
    return this.saasService.getUsageSummary(req.user.tenantId, id, period);
  }

  @Patch(':id/suspend')
  @ApiOperation({ summary: 'Suspender licença' })
  suspend(@Param('id') id: string, @Request() req: any) {
    return this.saasService.suspendLicense(req.user.tenantId, id);
  }

  @Patch(':id/reactivate')
  @ApiOperation({ summary: 'Reativar licença suspensa' })
  reactivate(@Param('id') id: string, @Request() req: any) {
    return this.saasService.reactivateLicense(req.user.tenantId, id);
  }

  @Patch(':id/revoke')
  @ApiOperation({ summary: 'Revogar licença permanentemente' })
  revoke(@Param('id') id: string, @Body() dto: RevokeReasonDto, @Request() req: any) {
    return this.saasService.revokeLicense(req.user.tenantId, id, dto);
  }

  @Post(':id/close-period')
  @ApiOperation({ summary: 'Fechar período de faturamento e gerar resumo de cobrança' })
  closePeriod(@Param('id') id: string, @Body('period') period: string, @Request() req: any) {
    return this.saasService.closeBillingPeriod(req.user.tenantId, id, period);
  }
}

@ApiTags('Gestão SaaS — API Keys')
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'))
@Controller('saas/licenses/:licenseId/keys')
export class SaasApiKeysController {
  constructor(private readonly saasService: SaasService) {}

  @Post()
  @ApiOperation({ summary: 'Criar API Key para a licença (retorna plain key uma única vez)' })
  create(@Param('licenseId') licenseId: string, @Body() dto: CreateApiKeyDto, @Request() req: any) {
    return this.saasService.createApiKey(req.user.tenantId, licenseId, dto);
  }

  @Get()
  @ApiOperation({ summary: 'Listar API Keys da licença' })
  list(@Param('licenseId') licenseId: string, @Request() req: any) {
    return this.saasService.listApiKeys(req.user.tenantId, licenseId);
  }

  @Delete(':keyId')
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Revogar API Key' })
  revoke(@Param('licenseId') licenseId: string, @Param('keyId') keyId: string, @Request() req: any) {
    return this.saasService.revokeApiKey(req.user.tenantId, licenseId, keyId);
  }
}

@ApiTags('Gestão SaaS — Endpoints')
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'))
@Controller('saas/licenses/:licenseId/endpoints')
export class SaasEndpointsController {
  constructor(private readonly saasService: SaasService) {}

  @Post()
  @ApiOperation({ summary: 'Registrar endpoint permitido para a licença' })
  add(@Param('licenseId') licenseId: string, @Body() dto: AddEndpointDto, @Request() req: any) {
    return this.saasService.addEndpoint(req.user.tenantId, licenseId, dto);
  }

  @Get()
  @ApiOperation({ summary: 'Listar endpoints da licença' })
  list(@Param('licenseId') licenseId: string, @Request() req: any) {
    return this.saasService.listEndpoints(req.user.tenantId, licenseId);
  }

  @Delete(':endpointId')
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Remover endpoint' })
  remove(
    @Param('licenseId') licenseId: string,
    @Param('endpointId') endpointId: string,
    @Request() req: any,
  ) {
    return this.saasService.removeEndpoint(req.user.tenantId, licenseId, endpointId);
  }
}

// ============================================================
// MODULE
// ============================================================
@Module({
  imports: [
    TypeOrmModule.forFeature([
      SaasLicense, SaasApiKey,
      SaasEndpoint, SaasUsageEvent, SaasUsageSummary,
      Tenant, User, UserTenantMembership,
    ]),
  ],
  controllers: [
    SaasLicensesController,
    SaasApiKeysController,
    SaasEndpointsController,
  ],
  providers: [SaasService],
  exports: [SaasService],
})
export class SaasModule {}
