#!/bin/bash

# CSV file structure:
# HOST RECORDTYPE POINTER EXTRA

# CSV field explanation
# RECORDTYPE: A, AAAA, CNAME and TXT will be imported. Otehr types will be ignored
# HOST_IMPORT: Subdomain of $DOMAIN
# POINTER: Value of the record (IP, Domain, or String)
# EXTRA: Will be ignored, since ist only relevant for SRV Records

# General notes on CSV
# Use DNS zone export for $DOMAIN from KIS
# Delimiter is ',', since this is what the KIS export uses
# Script will autumatically replace source IPv4 and IPv6 with destination IPv4 and IPv6, when/if provided by -4 (mandatory) and -6 (optional)

# Usage
# Clone the he_migration_cwh_fms_plesk repo from code.wartung.xyz to /tmp/
# run /tmp/he_migration_cwh_fms_plesk/update_server_plesk_migration_cwh.sh to make sure the server is setup correctly
# Save the csv DNS zone export for $DOMAIN from KIS to /tmp/migration_csv
# run /tmp/he_migration_cwh_fms_plesk/import_dns_plesk_kis_zone_export.sh -f /tmp/migration_csv/MY_ZONE_EXPORT.csv -d DOMAIN.TLD -4 1.2.3.4 -6 2001:db8:3333:4444:5555:6666:7777:8888

# Ensure the log directory exists
mkdir -p /tmp/migration_logs/

# Get the filename of current script and strip .sh from the end
SCRIPT_FILE_NAME=$(basename "$0" .sh)

# Create the log and error filenames
LOG_FILE_NAME="/tmp/migration_logs/$SCRIPT_FILE_NAME.log"
ERR_FILE_NAME="/tmp/migration_logs/$SCRIPT_FILE_NAME.err"

# Print info about logging
echo "STDOUT redirected to $LOG_FILE_NAME"
echo "STDERR redirected to $ERR_FILE_NAME"

# Parse command-line arguments
while [[ $# -gt 0 ]]; do
    case "$1" in
        -f) CSV_FILE="$2"; shift 2 ;;
        -d) DOMAIN="$2"; shift 2 ;;
        -4) IPV4_SRC="$2"; shift 2 ;;
        -6) IPV6_SRC="$2"; shift 2 ;;
        *) usage ;;
        esac
done

# Check if all required command-line arguments were provided and are non-zero
if [ -z "$CSV_FILE" ] || [ -z "$DOMAIN" ] || [ -z "$IPV4_SRC" ]; then
    usage
fi

# Check if the CSV file exists
if [ ! -f "$CSV_FILE" ]; then
    echo "Error: File $CSV_FILE does not exist."
    exit 1
fi

# Function to display usage, if none or non existing command-line arguments are provided
function usage() {
    echo "Usage: $0 -f <csv_file> -d <domain> -4 <old ipv4 address> -6 <old ipv6 address (optional)>"
    exit 1
}

# Making sure CSV files formatting is correct
echo "Checking $CSV_FILE for BOM, CRLF and Empty Lines"
  # Remove BOM (Byte Order Mark) from $CSV_FILE
  sed -i '1s/^\xEF\xBB\xBF//' "$CSV_FILE"
  
  # Remove CRLF (Windows Line Endings) from $CSV_FILE
  sed -i 's/\r$//' "$CSV_FILE"

  # Remove empty lines
  sed -i '/^$/d' "$CSV_FILE"
echo "Done converting $CSV_FILE"

# Function to check if a record for this host and type already exists in the domains DNS Zone in Plesk
function record_exists() {
    local RECORD_EXIST_HOST=$1
    local RECORD_EXIST_RECORDTYPE=$2
    local RECORD_EXIST_POINTER=$3

    if [[ "$RECORD_EXIST_RECORDTYPE" == "TXT" ]]; then
        if [[ "$RECORD_EXIST_POINTER" == *"spf"* || "$RECORD_EXIST_POINTER" == *"DMARC"* ]]; then
            if plesk bin dns --info "$DOMAIN" | grep -E "^$RECORD_EXIST_HOST" | grep -w "$RECORD_EXIST_RECORDTYPE" | grep -q "v=spf\|v=DMARC1"; then
                FAILED+=("$RECORD_EXIST_HOST.$DOMAIN ($RECORD_EXIST_RECORDTYPE) - Existing SPF/DMARC conflict")
                return 1
            fi
        else
            return 0
        fi
    else
        if [[ -n $RECORD_EXIST_HOST ]]; then
            if plesk bin dns --info "$DOMAIN" | grep -E "^$RECORD_EXIST_HOST" | grep -q -w "$RECORD_EXIST_RECORDTYPE\|CNAME"; then
                FAILED+=("$RECORD_EXIST_HOST.$DOMAIN ($RECORD_EXIST_RECORDTYPE) - Existing $RECORD_EXIST_RECORDTYPE/CNAME conflict")
                return 1
            else
                return 0
            fi
        else
            if plesk bin dns --info "$DOMAIN" | grep -E "^$DOMAIN" | grep -q -w "$RECORD_EXIST_RECORDTYPE\|CNAME"; then
                FAILED+=("$RECORD_EXIST_HOST.$DOMAIN ($RECORD_EXIST_RECORDTYPE) - Existing $RECORD_EXIST_RECORDTYPE/CNAME conflict")
                return 1
            else
                return 0
            fi
        fi
    fi
    return $?
}

# Function to add a DNS record
add_dns_record() {
    local ADD_DNS_RECORD_TYPE="$1"
    local ADD_DNS_RECORD_HOSTNAME="$2"
    local ADD_DNS_RECORD_POINTER="${3//\"/}"

    echo "Adding $ADD_DNS_RECORD_TYPE record for $ADD_DNS_RECORD_HOSTNAME to $DOMAIN with pointer/value $ADD_DNS_RECORD_POINTER" 
    if [[ "$ADD_DNS_RECORD_TYPE" == "A" && "$ADD_DNS_RECORD_POINTER" == "$IPV4_SRC" ]]; then
            if [[ "$ADD_DNS_RECORD_POINTER" == "$IPV4_SRC" ]]; then
                plesk bin dns -a "$DOMAIN" -a "$ADD_DNS_RECORD_HOSTNAME" -ip "$IPV4_DST" >> "$LOG_FILE_NAME" 2>> "$ERR_FILE_NAME"
            else
                plesk bin dns -a "$DOMAIN" -a "$ADD_DNS_RECORD_HOSTNAME" -ip "$ADD_DNS_RECORD_POINTER" >> "$LOG_FILE_NAME" 2>> "$ERR_FILE_NAME"
            fi
    elif [[ "$ADD_DNS_RECORD_TYPE" == "AAAA" && "$ADD_DNS_RECORD_POINTER" == "$IPV6_SRC" ]]; then
             if [[ "$ADD_DNS_RECORD_POINTER" == "$IPV6_SRC" ]]; then
                plesk bin dns -a "$DOMAIN" -aaaa "$ADD_DNS_RECORD_HOSTNAME" -ip "$IPV6_DST" >> "$LOG_FILE_NAME" 2>> "$ERR_FILE_NAME"
            else
                plesk bin dns -a "$DOMAIN" -aaaa "$ADD_DNS_RECORD_HOSTNAME" -ip "$ADD_DNS_RECORD_POINTER" >> "$LOG_FILE_NAME" 2>> "$ERR_FILE_NAME"
            fi
    elif [[ "$ADD_DNS_RECORD_TYPE" == "CNAME" ]]; then
        plesk bin dns -a "$DOMAIN" -cname "$ADD_DNS_RECORD_HOSTNAME" -canonical "$ADD_DNS_RECORD_POINTER" >> "$LOG_FILE_NAME" 2>> "$ERR_FILE_NAME"
    elif [[ "$ADD_DNS_RECORD_TYPE" == "TXT" ]]; then
        plesk bin dns -a "$DOMAIN" -domain "$ADD_DNS_RECORD_HOSTNAME" -txt "$ADD_DNS_RECORD_POINTER" >> "$LOG_FILE_NAME" 2>> "$ERR_FILE_NAME"
    else
        FAILED+=("$ADD_DNS_RECORD_HOSTNAME.$DOMAIN - $ADD_DNS_RECORD_TYPE - Unknown recordtype")
    fi
}

# Arrays for summary
SUCCESSFUL=()
FAILED=()

# Get Destination Servers IP addresses
IPV4_DST=$(plesk bin ipmanage --ip_list | awk '$2 == "S" {print $3}' | grep '\.' | cut -d ':' -f2 | cut -d '/' -f1)
IPV6_DST=$(plesk bin ipmanage --ip_list | awk '$2 == "S" {print $3}' | awk -F: '{sub($1 ":", ""); print}' | grep ':' | cut -d'/' -f1)

# Check if the DNS zone for the domain exists and DNS management is enabled for the domain
DNS_ZONE_STATUS=$(plesk bin dns --info "$DOMAIN" 2>/dev/null | grep -c "Status: enabled\|SUCCESS: Getting information")
if [ "$DNS_ZONE_STATUS" -eq 0 ]; then
    echo "Error: No existing or enabled DNS zone found for domain $DOMAIN."
    exit 1
fi

# Read CSV and process each line
HEADER_PROCESSED=false
while IFS=',' read -r RECORDTYPE HOST_IMPORT POINTER EXTRA; do
    # Skip empty lines
    if [[ -z "$RECORDTYPE" || -z "POINTER"  ]]; then
        continue
    fi
    # Skip the header line if it exists
    if [[ "$HEADER_PROCESSED" == false ]]; then
        if [[ "$RECORDTYPE" == "recordtyp" && "$HOST_IMPORT" == "hostname" && "$POINTER" == "pointer" && "$EXTRA" == "extra" ]]; then
            HEADER_PROCESSED=true
            continue
        fi
        HEADER_PROCESSED=true
    fi
    # Skip record types that should not be imported
    if [[ "$RECORDTYPE" == "NS" || "$RECORDTYPE" == "MX" || "$RECORDTYPE" == "CAA" || "$RECORDTYPE" == "DS" || "$RECORDTYPE" == "PTR" || "$RECORDTYPE" == "SOA" || "$RECORDTYPE" == "SRV" ]]; then
        FAILED+=("$HOST_IMPORT ($RECORDTYPE) - Unsupported recordtype")
        continue
    else
        # Check if the record already exists
        if record_exists "$HOST_IMPORT" "$RECORDTYPE" "$POINTER"; then
            # Create record
            if add_dns_record "$RECORDTYPE" "$HOST_IMPORT" "$POINTER" >/dev/null 2>&1; then
                SUCCESSFUL+=("$HOST_IMPORT.$DOMAIN ($RECORDTYPE) - ${POINTER:0:15} ")
            else
                FAILED+=("$HOST_IMPORT.$DOMAIN ($RECORDTYPE) ${POINTER:0:15} - Creation failed. Double? ")
            fi
        fi
    fi
done < "$CSV_FILE"

# Print summary
echo "Summary:"
echo "---------"
echo "Successfully created entries (Pointer shortend to 15 chars):"
for ITEM in "${SUCCESSFUL[@]}"; do
  echo "$ITEM"
done
echo "---------"
echo "Failed to create entries (Pointer shortend to 15 chars):"
for ITEM in "${FAILED[@]}"; do
  echo "$ITEM"
done
echo "---------"