import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { Domain } from '../entities/domain.entity';

export interface ResolvedDomain {
  domainId: number;
  corpId: number;
  hostname: string;
}

/**
 * Resolves request → (corp_id, domain_id) by matching the request's hostname
 * against the `domains` table. The proxy strips `Host` upstream, so we read
 * Origin first, then Referer as a fallback.
 *
 * Unknown hosts return null — the caller decides whether to drop the event or
 * persist with NULL dimensions. Default: drop, to keep the dataset clean.
 */
@Injectable()
export class DomainResolverService {
  private readonly logger = new Logger(DomainResolverService.name);

  /** hostname → resolved row. Reloaded on miss. */
  private cache = new Map<string, ResolvedDomain | null>();

  constructor(
    @InjectRepository(Domain)
    private readonly domainRepo: Repository<Domain>,
  ) {}

  /**
   * Extract the hostname from the most reliable header available.
   * Returns lowercase, no port, no path.
   */
  hostnameFromHeaders(headers: Record<string, string | string[] | undefined>): string | null {
    const pick = (h: string | string[] | undefined): string | undefined => {
      if (Array.isArray(h)) return h[0];
      return h;
    };
    const origin = pick(headers['origin']);
    const referer = pick(headers['referer']);
    const host = pick(headers['host']);
    const candidate = origin ?? referer ?? host;
    if (!candidate) return null;
    try {
      const u = candidate.includes('://') ? new URL(candidate) : new URL(`http://${candidate}`);
      return u.hostname.toLowerCase();
    } catch {
      return null;
    }
  }

  /** Look up a domain row by hostname. */
  async resolve(hostname: string | null): Promise<ResolvedDomain | null> {
    if (!hostname) return null;
    const cached = this.cache.get(hostname);
    if (cached !== undefined) return cached;

    const row = await this.domainRepo.findOne({ where: { hostname } });
    const resolved: ResolvedDomain | null = row
      ? { domainId: row.id, corpId: row.corpId, hostname: row.hostname }
      : null;
    this.cache.set(hostname, resolved);
    if (!resolved) {
      this.logger.warn({ hostname }, 'Unknown domain — event will be dropped or untagged');
    }
    return resolved;
  }
}
