import { logger } from '../utils/logger';

// --- Types ---

export interface TailscaleDevice {
  id: string;
  name: string;        // FQDN hostname
  addresses: string[]; // IPv4 + IPv6 Tailscale addresses
  os: string;          // "android", "linux", "windows", etc.
  hostname: string;    // Short hostname
  online: boolean;
  lastSeen: string;    // ISO 8601
  clientVersion?: string;
  updateAvailable?: boolean;
  tags?: string[];
}

// --- Client ---

class TailscaleClient {
  private apiKey = '';
  private tailnet = '-'; // "-" = default tailnet (Tailscale API convention)

  private get baseUrl(): string {
    return 'https://api.tailscale.com/api/v2';
  }

  /** Configure client with an API key (and optional tailnet override). */
  configure(apiKey: string, tailnet?: string): void {
    this.apiKey = apiKey;
    if (tailnet) this.tailnet = tailnet;
  }

  /** Load configuration from DB settings. */
  async configureFromDb(): Promise<void> {
    const { siteSettingsService } = await import('../modules/settings/settings.service');
    const settings = await siteSettingsService.get();
    this.apiKey = settings.smsTailscaleApiKey || '';
    if (settings.smsTailscaleTailnet) {
      this.tailnet = settings.smsTailscaleTailnet;
    }
  }

  get configured(): boolean {
    return !!this.apiKey;
  }

  private async request<T>(method: string, path: string): Promise<T> {
    if (!this.apiKey) {
      throw new Error('Tailscale API not configured. Provide an API key.');
    }

    const url = `${this.baseUrl}${path}`;
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 10000);

    try {
      const res = await fetch(url, {
        method,
        headers: {
          'Authorization': `Bearer ${this.apiKey}`,
          'Content-Type': 'application/json',
        },
        signal: controller.signal,
      });

      if (!res.ok) {
        const text = await res.text().catch(() => '');
        throw new Error(`Tailscale API ${method} ${path} returned ${res.status}: ${text}`);
      }

      const contentType = res.headers.get('content-type') || '';
      if (contentType.includes('application/json')) {
        return await res.json() as T;
      }
      return {} as T;
    } finally {
      clearTimeout(timeout);
    }
  }

  // --- Devices ---

  async listDevices(): Promise<TailscaleDevice[]> {
    const res = await this.request<{ devices?: TailscaleDevice[] }>(
      'GET',
      `/tailnet/${encodeURIComponent(this.tailnet)}/devices`,
    );
    return res.devices || [];
  }

  async getDevice(deviceId: string): Promise<TailscaleDevice> {
    return this.request<TailscaleDevice>('GET', `/device/${encodeURIComponent(deviceId)}`);
  }

  // --- Helpers ---

  /** Filter devices by Android OS. */
  filterAndroidDevices(devices: TailscaleDevice[]): TailscaleDevice[] {
    return devices.filter(d => d.os.toLowerCase() === 'android');
  }

  /** Extract the first IPv4 address from a device's address list. */
  getDeviceIpv4(device: TailscaleDevice): string | null {
    for (const addr of device.addresses) {
      // IPv4 addresses don't contain ':'
      if (!addr.includes(':')) {
        return addr;
      }
    }
    return null;
  }

  /** Quick health check: tries to list devices. */
  async healthCheck(): Promise<boolean> {
    try {
      await this.listDevices();
      return true;
    } catch (err) {
      logger.warn('Tailscale health check failed:', err instanceof Error ? err.message : err);
      return false;
    }
  }
}

export { TailscaleClient };
export const tailscaleClient = new TailscaleClient();
