import logging
from typing import Tuple

import zonefilegen.core
import zonefilegen.parsing

def build_soa_record(soa_dict: dict, serial_number: int) -> zonefilegen.core.ResourceRecord:
    """
    Constructs a special SOA record with a specified serial number
    """
    soa_rec = zonefilegen.core.ResourceRecord()
    soa_rec.name = "@"
    soa_rec.ttl = None
    soa_rec.record_class = 'IN'
    soa_rec.record_type = 'SOA'
    soa_rec.data = f"{soa_dict['mname']} {soa_dict['rname']} ("\
        f"{serial_number} "\
        f"{soa_dict['refresh']} "\
        f"{soa_dict['retry']} " \
        f"{soa_dict['expire']} " \
        f"{soa_dict['negative_caching_ttl']})"
    return soa_rec

def build_reverse_zone(network, ptr_candidates: Tuple, default_ttl: int) -> zonefilegen.core.Zone:
    """
    Checks a set of addresses if they are part of a network and
    include them as PTR records in a reverse zone for that network in such case.
    """
    rev_zone = zonefilegen.core.Zone(zonefilegen.parsing.get_rev_zone_name(network), default_ttl)
    included_ptr_names = set()

    for (name, ttl, addr) in ptr_candidates:
        if addr in network:
            rec = zonefilegen.core.ResourceRecord()
            rec.name = zonefilegen.parsing.get_rev_ptr_name(addr, network.prefixlen)
            rec.record_type = 'PTR'
            rec.record_class = 'IN'
            rec.ttl = ttl
            rec.data = name
            if rec.name not in included_ptr_names:
                included_ptr_names.add(rec.name)
                rev_zone.records.append(rec)
    return rev_zone

def build_fwd_zone(zone_name: str, rrset_dict: dict, default_ttl: int) -> zonefilegen.core.Zone:
    """
    Builds a forward DNS zone from a set of records
    """
    fwd_zone = zonefilegen.core.Zone(zone_name, default_ttl)
    
    for rrset in rrset_dict:
        if rrset['name'].endswith('.'):
            name = rrset['name']
        elif rrset['name'] == '@':
            name = zone_name
        else:
            name = f"{rrset['name']}.{zone_name}"
     
        if type(rrset['data']) is list:
            record_data_arr = rrset['data']
        else:
            record_data_arr = [rrset['data']]
     
        for record_data in record_data_arr:
            record = zonefilegen.core.ResourceRecord()
            record.name = name
            record.record_type = rrset['type']
            if not record.record_type in zonefilegen.core.RECORD_TYPES:
                logging.critical(f"Invalid type in record for {record.name} : {record.record_type}")
                exit(1)
            if 'ttl' in rrset:
                record.ttl = rrset['ttl']
            record.record_class = 'IN'
            record.data = record_data
     
            fwd_zone.records.append(record)
    return fwd_zone

def generate_header(digest: str):
    return f"; Generated by zonefilegen, INPUT_DIGEST: {digest}"