# CoreDNS API Client
# Client for orchestrator DNS API endpoints

# ../utils/log.nu does not exist — dangling import removed (ADR-025 L2).
use lib_provisioning/config/loader.nu [get-config]

# Call orchestrator DNS API
export def call-dns-api [
    endpoint: string          # API endpoint path (e.g., "/dns/record")
    method: string = "GET"    # HTTP method
    body?: record             # Request body
    --timeout: int = 30       # Request timeout in seconds
] -> record {
    log debug $"Calling DNS API: ($method) ($endpoint)"

    let config = get-config
    let coredns_config = $config.coredns? | default {}
    let api_endpoint = $coredns_config.dynamic_updates?.api_endpoint? | default "http://localhost:8080/dns"

    let full_url = $"($api_endpoint)($endpoint)"

    let result = (do {
        match $method {
            "GET" => {
                http get -t $timeout $full_url
            }
            "POST" => {
                if $body != null {
                    http post -t $timeout -c "application/json" $full_url ($body | to json)
                } else {
                    http post -t $timeout $full_url
                }
            }
            "PUT" => {
                if $body != null {
                    http put -t $timeout -c "application/json" $full_url ($body | to json)
                } else {
                    http put -t $timeout $full_url
                }
            }
            "DELETE" => {
                http delete -t $timeout $full_url
            }
            _ => {
                log error $"Unsupported HTTP method: [$method]"
                error make {msg: "Unsupported method"}
            }
        }
    } | complete)

    if $result.exit_code == 0 {
        {
            success: true
            response: $result.stdout
        }
    } else {
        log error $"DNS API call failed: [$result.stderr]"
        {
            success: false
            error: $result.stderr
        }
    }
}

# Add DNS record via API
export def api-add-record [
    hostname: string          # Hostname
    ip_address: string        # IP address
    record_type: string = "A" # Record type
    --zone: string = "provisioning.local"
    --ttl: int = 300
    --comment: string = ""
    --check
] -> bool {
    log info $"Adding DNS record via API: ($hostname) -> ($ip_address)"

    if $check {
        log info "Check mode: Would add DNS record via API"
        return true
    }

    let body = {
        zone: $zone
        hostname: $hostname
        record_type: $record_type
        value: $ip_address
        ttl: $ttl
        comment: $comment
    }

    let result = call-dns-api "/record" "POST" $body

    if $result.success {
        log info $"DNS record added via API: ($hostname)"
        true
    } else {
        log error $"Failed to add DNS record via API: ($result.error)"
        false
    }
}

# Remove DNS record via API
export def api-remove-record [
    hostname: string          # Hostname
    --zone: string = "provisioning.local"
    --check
] -> bool {
    log info $"Removing DNS record via API: ($hostname)"

    if $check {
        log info "Check mode: Would remove DNS record via API"
        return true
    }

    let body = {
        zone: $zone
        hostname: $hostname
    }

    let result = call-dns-api "/record" "DELETE" $body

    if $result.success {
        log info $"DNS record removed via API: ($hostname)"
        true
    } else {
        log error $"Failed to remove DNS record via API: ($result.error)"
        false
    }
}

# Update DNS record via API
export def api-update-record [
    hostname: string          # Hostname
    ip_address: string        # New IP address
    record_type: string = "A" # Record type
    --zone: string = "provisioning.local"
    --ttl: int = 300
    --comment: string = ""
    --check
] -> bool {
    log info $"Updating DNS record via API: ($hostname) -> ($ip_address)"

    if $check {
        log info "Check mode: Would update DNS record via API"
        return true
    }

    let body = {
        zone: $zone
        hostname: $hostname
        record_type: $record_type
        value: $ip_address
        ttl: $ttl
        comment: $comment
    }

    let result = call-dns-api "/record" "PUT" $body

    if $result.success {
        log info $"DNS record updated via API: ($hostname)"
        true
    } else {
        log error $"Failed to update DNS record via API: ($result.error)"
        false
    }
}

# List DNS records via API
export def api-list-records [
    --zone: string = "provisioning.local"
    --format: string = "table"
] -> any {
    log debug $"Listing DNS records via API for zone: ($zone)"

    let result = call-dns-api $"/records?zone=($zone)" "GET"

    if $result.success {
        let records = $result.response

        match $format {
            "json" => { $records | to json }
            "yaml" => { $records | to yaml }
            _ => { $records }
        }
    } else {
        log error $"Failed to list DNS records via API: ($result.error)"
        []
    }
}

# Get DNS zones via API
export def api-list-zones [] -> list {
    log debug "Listing DNS zones via API"

    let result = call-dns-api "/zones" "GET"

    if $result.success {
        $result.response
    } else {
        log error $"Failed to list DNS zones via API: ($result.error)"
        []
    }
}

# Reload CoreDNS via API
export def api-reload-coredns [] -> bool {
    log info "Reloading CoreDNS via API"

    let result = call-dns-api "/reload" "POST"

    if $result.success {
        log info "CoreDNS reloaded via API"
        true
    } else {
        log error $"Failed to reload CoreDNS via API: ($result.error)"
        false
    }
}

# Check DNS health via API
export def api-check-health [] -> record {
    log debug "Checking DNS health via API"

    let result = call-dns-api "/health" "GET"

    if $result.success {
        $result.response
    } else {
        log error $"Failed to check DNS health via API: ($result.error)"
        {
            healthy: false
            error: $result.error
        }
    }
}

# Batch add DNS records via API
export def api-batch-add-records [
    records: list             # List of {hostname, ip_address, record_type, zone, ttl, comment}
    --check
] -> record {
    log info $"Batch adding ($records | length) DNS records via API"

    if $check {
        log info "Check mode: Would batch add DNS records via API"
        return {
            total: ($records | length)
            added: ($records | length)
            failed: 0
            check_mode: true
        }
    }

    let body = {
        records: $records
    }

    let result = call-dns-api "/records/batch" "POST" $body

    if $result.success {
        log info "DNS records batch added via API"
        $result.response
    } else {
        log error $"Failed to batch add DNS records via API: ($result.error)"
        {
            total: ($records | length)
            added: 0
            failed: ($records | length)
            error: $result.error
        }
    }
}

# Batch remove DNS records via API
export def api-batch-remove-records [
    hostnames: list<string>   # List of hostnames
    --zone: string = "provisioning.local"
    --check
] -> record {
    log info $"Batch removing ($hostnames | length) DNS records via API"

    if $check {
        log info "Check mode: Would batch remove DNS records via API"
        return {
            total: ($hostnames | length)
            removed: ($hostnames | length)
            failed: 0
            check_mode: true
        }
    }

    let body = {
        zone: $zone
        hostnames: $hostnames
    }

    let result = call-dns-api "/records/batch" "DELETE" $body

    if $result.success {
        log info "DNS records batch removed via API"
        $result.response
    } else {
        log error $"Failed to batch remove DNS records via API: ($result.error)"
        {
            total: ($hostnames | length)
            removed: 0
            failed: ($hostnames | length)
            error: $result.error
        }
    }
}

# Query DNS via API
export def api-query-dns [
    hostname: string          # Hostname to query
    --type: string = "A"      # Record type
    --zone: string = "provisioning.local"
] -> record {
    log debug $"Querying DNS via API: ($hostname) ($type)"

    let result = call-dns-api $"/query?hostname=($hostname)&type=($type)&zone=($zone)" "GET"

    if $result.success {
        $result.response
    } else {
        log error $"Failed to query DNS via API: ($result.error)"
        {
            hostname: $hostname
            type: $type
            found: false
            error: $result.error
        }
    }
}

# Export zone file via API
export def api-export-zone [
    zone: string              # Zone name
    --output: string = ""     # Output file path (optional)
] -> string {
    log debug $"Exporting zone via API: ($zone)"

    let result = call-dns-api $"/zones/($zone)/export" "GET"

    if $result.success {
        let zone_content = $result.response.content

        if ($output | is-not-empty) {
            $zone_content | save -f $output
            log info $"Zone exported to ($output)"
        }

        $zone_content
    } else {
        log error $"Failed to export zone via API: ($result.error)"
        ""
    }
}

# Import zone file via API
export def api-import-zone [
    zone: string              # Zone name
    zone_file: string         # Path to zone file
    --check
] -> bool {
    log info $"Importing zone via API: ($zone)"

    if $check {
        log info "Check mode: Would import zone via API"
        return true
    }

    if not ($zone_file | path exists) {
        log error $"Zone file not found: ($zone_file)"
        return false
    }

    let zone_content = open $zone_file

    let body = {
        zone: $zone
        content: $zone_content
    }

    let result = call-dns-api "/zones/import" "POST" $body

    if $result.success {
        log info $"Zone imported via API: ($zone)"
        true
    } else {
        log error $"Failed to import zone via API: ($result.error)"
        false
    }
}

# Get DNS statistics via API
export def api-get-stats [] -> record {
    log debug "Getting DNS statistics via API"

    let result = call-dns-api "/stats" "GET"

    if $result.success {
        $result.response
    } else {
        log error $"Failed to get DNS statistics via API: ($result.error)"
        {}
    }
}

# Validate zone via API
export def api-validate-zone [
    zone: string              # Zone name
] -> record {
    log debug $"Validating zone via API: ($zone)"

    let result = call-dns-api $"/zones/($zone)/validate" "GET"

    if $result.success {
        $result.response
    } else {
        log error $"Failed to validate zone via API: ($result.error)"
        {
            valid: false
            error: $result.error
        }
    }
}
