import { Injectable, NestMiddleware, BadRequestException } from '@nestjs/common';
  import { Request, Response, NextFunction } from 'express';
  import { DataSource, Repository } from 'typeorm';
  import { Inject } from '@nestjs/common';
  import { LANDLORD_DATA_SOURCE } from '../database/database.module';
  import { Tenant } from '../database/landlord/entities/tenant.entity';
  import { Domain } from '../database/landlord/entities/domain.entity';
  import { tenantStorage } from '../database/tenant-context';

  const SKIP_PREFIXES = ['/api/health', '/api/master', '/api/tenants/register'];

  @Injectable()
  export class TenantMiddleware implements NestMiddleware {
    private readonly tenantRepo: Repository<Tenant>;
    private readonly domainRepo: Repository<Domain>;

    constructor(@Inject(LANDLORD_DATA_SOURCE) private readonly landlord: DataSource) {
      this.tenantRepo = landlord.getRepository(Tenant);
      this.domainRepo = landlord.getRepository(Domain);
    }

    async use(req: Request, res: Response, next: NextFunction): Promise<void> {
      const path = req.originalUrl.split('?')[0];
      if (SKIP_PREFIXES.some((p) => path.startsWith(p))) {
        return next();
      }

      const subdomain = this.resolveSubdomain(req);
      if (!subdomain) {
        // Allow unauthenticated public endpoints to pass without tenant
        return next();
      }

      const tenant = await this.tenantRepo.findOne({ where: { subdomain } });
      if (!tenant) {
        throw new BadRequestException(`Unknown tenant: ${subdomain}`);
      }
      if (tenant.status !== 'active') {
        throw new BadRequestException(`Tenant "${subdomain}" is not active`);
      }

      res.setHeader('X-Tenant-Id', tenant.id);
      tenantStorage.run({ tenantId: tenant.id, subdomain: tenant.subdomain }, () =>
        next(),
      );
    }

    private resolveSubdomain(req: Request): string | undefined {
      const headerVal = req.headers['x-tenant-subdomain'];
      if (typeof headerVal === 'string' && headerVal.trim()) {
        return headerVal.trim().toLowerCase();
      }
      const host = (req.headers['x-forwarded-host'] as string | undefined) ?? req.headers.host;
      if (!host) return undefined;
      // e.g. "abc.example.com" -> "abc"
      const hostname = host.split(':')[0];
      const parts = hostname.split('.');
      if (parts.length >= 3) return parts[0].toLowerCase();
      return undefined;
    }
  }
  