import { Injectable, NestMiddleware, UnauthorizedException } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { ClsService } from 'nestjs-cls';
import { CLS_TENANT_ID } from '../cls/cls.constants';

/**
 * TenantMiddleware — resolves tenant_id from subdomain and stores in CLS.
 *
 * Per CLAUDE.md:
 * - tenant_id resolved automatically via TenantMiddleware (subdomain in prod)
 * - Stored in request-scoped async context via ClsService (nestjs-cls)
 * - No setTenantId() calls — context propagation is fully automatic
 *
 * TODO: Look up tenant_id (UUID) from DB by subdomain once traffic grows.
 */
@Injectable()
export class TenantMiddleware implements NestMiddleware {
  constructor(private readonly cls: ClsService) {}

  use(req: Request, _res: Response, next: NextFunction): void {
    const host = req.headers.host || '';
    const subdomain = this.extractSubdomain(host);

    if (!subdomain) {
      throw new UnauthorizedException('Tenant could not be resolved from host');
    }

    // Store in CLS — available everywhere downstream automatically
    this.cls.set(CLS_TENANT_ID, subdomain);

    next();
  }

  private extractSubdomain(host: string): string | null {
    const hostname = host.split(':')[0];

    if (hostname === 'localhost' || hostname === '127.0.0.1') {
      return null;
    }

    const parts = hostname.split('.');
    if (parts.length >= 3) {
      return parts[0];
    }

    return null;
  }
}

/**
 * DevTenantMiddleware — local development fallback.
 * Uses X-Tenant-Id header and stores in CLS.
 */
@Injectable()
export class DevTenantMiddleware implements NestMiddleware {
  constructor(private readonly cls: ClsService) {}

  use(req: Request, _res: Response, next: NextFunction): void {
    const tenantId = req.headers['x-tenant-id'] as string;

    if (!tenantId) {
      throw new UnauthorizedException(
        'X-Tenant-Id header is required in development mode',
      );
    }

    this.cls.set(CLS_TENANT_ID, tenantId);

    next();
  }
}
