const HETZNER_API_BASE = 'https://api.hetzner.cloud/v1';

interface HetznerRRSet {
  id: string;
  name: string;
  type: string;
  ttl: number | null;
  zone: number;
  records: { value: string; comment?: string }[];
}

interface CreateRRSetRequest {
  name: string;
  type: 'A' | 'AAAA' | 'CNAME' | 'TXT' | 'MX' | 'NS';
  ttl?: number;
  records: { value: string; comment?: string }[];
}

interface HetznerZonesResponse {
  zones: { id: number; name: string }[];
  meta: { pagination: { total_entries: number } };
}

interface HetznerRRSetsResponse {
  rrsets: HetznerRRSet[];
  meta: { pagination: { total_entries: number } };
}

export class HetznerDNSClient {
  private apiToken: string;
  private zoneId: string;

  constructor(apiToken: string, zoneId: string) {
    if (!apiToken) {
      throw new Error('HETZNER_API_TOKEN is required');
    }
    if (!zoneId) {
      throw new Error('HETZNER_ZONE_ID is required');
    }
    this.apiToken = apiToken;
    this.zoneId = zoneId;
  }

  private async request<T>(
    method: string,
    endpoint: string,
    body?: unknown
  ): Promise<T> {
    const url = `${HETZNER_API_BASE}${endpoint}`;
    
    const response = await fetch(url, {
      method,
      headers: {
        'Authorization': `Bearer ${this.apiToken}`,
        'Content-Type': 'application/json',
      },
      body: body ? JSON.stringify(body) : undefined,
    });

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`Hetzner API error (${response.status}): ${errorText}`);
    }

    return response.json() as Promise<T>;
  }

  async createARecord(subdomain: string, ip: string, ttl = 300): Promise<HetznerRRSet> {
    const rrset = await this.request<{ rrset: HetznerRRSet }>(
      'POST',
      `/zones/${this.zoneId}/rrsets`,
      {
        name: subdomain,
        type: 'A',
        ttl,
        records: [{ value: ip }],
      } satisfies CreateRRSetRequest
    );

    return rrset.rrset;
  }

  async getRRSets(type?: string): Promise<HetznerRRSet[]> {
    let endpoint = `/zones/${this.zoneId}/rrsets?per_page=100`;
    if (type) {
      endpoint += `&type=${type}`;
    }
    
    const data = await this.request<HetznerRRSetsResponse>('GET', endpoint);
    return data.rrsets || [];
  }

  async findRRSetByName(name: string, type = 'A'): Promise<HetznerRRSet | null> {
    const rrsets = await this.getRRSets(type);
    return rrsets.find(r => r.name === name) || null;
  }

  async deleteRRSet(name: string, type: string): Promise<void> {
    const rrsetId = encodeURIComponent(`${name}/${type}`);
    await this.request('DELETE', `/zones/${this.zoneId}/rrsets/${rrsetId}`);
  }

  async recordExists(subdomain: string): Promise<boolean> {
    const rrset = await this.findRRSetByName(subdomain);
    return rrset !== null;
  }

  async getZone(): Promise<{ id: number; name: string } | null> {
    try {
      const data = await this.request<{ zone: { id: number; name: string } }>(
        'GET',
        `/zones/${this.zoneId}`
      );
      return data.zone;
    } catch {
      return null;
    }
  }

  async testConnection(): Promise<{ success: boolean; message: string; recordCount?: number; zoneName?: string }> {
    try {
      const zone = await this.getZone();
      if (!zone) {
        return { success: false, message: 'Zone not found' };
      }
      
      const rrsets = await this.getRRSets();
      return {
        success: true,
        message: `Connected to Hetzner Cloud DNS API. Zone "${zone.name}" has ${rrsets.length} RRSets.`,
        recordCount: rrsets.length,
        zoneName: zone.name
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : 'Unknown error'
      };
    }
  }
}

export function createHetznerClient(): HetznerDNSClient {
  const apiToken = process.env.HETZNER_API_TOKEN;
  const zoneId = process.env.HETZNER_ZONE_ID;

  if (!apiToken) {
    throw new Error('HETZNER_API_TOKEN environment variable is not set');
  }
  if (!zoneId) {
    throw new Error('HETZNER_ZONE_ID environment variable is not set');
  }

  return new HetznerDNSClient(apiToken, zoneId);
}
