#!/usr/bin/env python3
"""
Alibaba Cloud DNS Record Manager
Supports: list, add, update, delete, enable, disable operations on Alidns records.

Usage:
    python alidns_manager.py list   --domain example.com [--rr www] [--type A]
    python alidns_manager.py add    --domain example.com --rr www --type A --value 1.2.3.4 [--ttl 600]
    python alidns_manager.py update --record-id 123456 --rr www --type A --value 5.6.7.8 [--ttl 600]
    python alidns_manager.py delete --record-id 123456
    python alidns_manager.py enable  --record-id 123456
    python alidns_manager.py disable --record-id 123456

Environment Variables:
    ALIBABA_CLOUD_ACCESS_KEY_ID     - RAM sub-user Access Key ID
    ALIBABA_CLOUD_ACCESS_KEY_SECRET - RAM sub-user Access Key Secret
"""

import argparse
import json
import os
import sys

try:
    from alibabacloud_alidns20150109.client import Client as AlidnsClient
    from alibabacloud_alidns20150109 import models as alidns_models
    from alibabacloud_tea_openapi import models as open_api_models
except ImportError:
    print("ERROR: Required packages not installed. Run:")
    print("  pip install alibabacloud_alidns20150109 alibabacloud_tea_openapi --break-system-packages")
    sys.exit(1)


def create_client(region_id: str = "cn-hangzhou") -> AlidnsClient:
    """Create an authenticated Alidns client."""
    access_key_id = os.environ.get("ALIBABA_CLOUD_ACCESS_KEY_ID")
    access_key_secret = os.environ.get("ALIBABA_CLOUD_ACCESS_KEY_SECRET")

    if not access_key_id or not access_key_secret:
        print("ERROR: Set ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET env vars.")
        sys.exit(1)

    config = open_api_models.Config(
        access_key_id=access_key_id,
        access_key_secret=access_key_secret,
    )
    config.endpoint = f"alidns.{region_id}.aliyuncs.com"
    return AlidnsClient(config)


def list_records(client: AlidnsClient, domain: str, rr: str = None, record_type: str = None, page_size: int = 100):
    """List all DNS records for a domain, with optional filtering."""
    request = alidns_models.DescribeDomainRecordsRequest(
        domain_name=domain,
        page_size=page_size,
    )
    if rr:
        request.rrkey_word = rr
    if record_type:
        request.type = record_type

    try:
        response = client.describe_domain_records(request)
        records = response.body.domain_records.record
        total = response.body.total_count

        print(f"\n📋 DNS Records for {domain} (Total: {total})\n")
        print(f"{'RecordId':<20} {'RR':<25} {'Type':<8} {'Value':<40} {'TTL':<6} {'Status'}")
        print("-" * 120)

        for r in records:
            status_icon = "✅" if r.status == "ENABLE" else "⏸️"
            rr_display = f"{r.rr}.{domain}" if r.rr != "@" else domain
            print(f"{r.record_id:<20} {rr_display:<25} {r.type:<8} {r.value:<40} {r.ttl:<6} {status_icon} {r.status}")

        return records
    except Exception as e:
        print(f"ERROR listing records: {e}")
        sys.exit(1)


def add_record(client: AlidnsClient, domain: str, rr: str, record_type: str, value: str, ttl: int = 600):
    """Add a new DNS record."""
    request = alidns_models.AddDomainRecordRequest(
        domain_name=domain,
        rr=rr,
        type=record_type,
        value=value,
        ttl=ttl,
    )

    try:
        response = client.add_domain_record(request)
        record_id = response.body.record_id
        fqdn = f"{rr}.{domain}" if rr != "@" else domain
        print(f"✅ Added: {fqdn} -> {record_type} {value} (TTL: {ttl}, RecordId: {record_id})")
        return record_id
    except Exception as e:
        error_msg = str(e)
        if "DomainRecordDuplicate" in error_msg:
            print(f"⚠️  Record already exists: {rr}.{domain} {record_type} {value}")
        elif "DomainRecordConflict" in error_msg:
            print(f"❌ Conflict: CNAME records cannot coexist with other record types for {rr}.{domain}")
        else:
            print(f"ERROR adding record: {e}")
        return None


def update_record(client: AlidnsClient, record_id: str, rr: str, record_type: str, value: str, ttl: int = 600):
    """Update an existing DNS record by RecordId."""
    request = alidns_models.UpdateDomainRecordRequest(
        record_id=record_id,
        rr=rr,
        type=record_type,
        value=value,
        ttl=ttl,
    )

    try:
        client.update_domain_record(request)
        print(f"✅ Updated RecordId {record_id}: {rr} -> {record_type} {value} (TTL: {ttl})")
    except Exception as e:
        print(f"ERROR updating record: {e}")


def delete_record(client: AlidnsClient, record_id: str):
    """Delete a DNS record by RecordId."""
    request = alidns_models.DeleteDomainRecordRequest(record_id=record_id)

    try:
        client.delete_domain_record(request)
        print(f"✅ Deleted RecordId: {record_id}")
    except Exception as e:
        print(f"ERROR deleting record: {e}")


def set_record_status(client: AlidnsClient, record_id: str, status: str):
    """Enable or disable a DNS record."""
    request = alidns_models.SetDomainRecordStatusRequest(
        record_id=record_id,
        status=status,  # "Enable" or "Disable"
    )

    try:
        client.set_domain_record_status(request)
        icon = "✅" if status == "Enable" else "⏸️"
        print(f"{icon} RecordId {record_id} status set to: {status}")
    except Exception as e:
        print(f"ERROR setting status: {e}")


def main():
    parser = argparse.ArgumentParser(description="Alibaba Cloud DNS Record Manager")
    subparsers = parser.add_subparsers(dest="action", help="Action to perform")

    # List
    list_parser = subparsers.add_parser("list", help="List DNS records")
    list_parser.add_argument("--domain", required=True, help="Domain name (e.g., gogenex.com)")
    list_parser.add_argument("--rr", help="Filter by subdomain prefix")
    list_parser.add_argument("--type", help="Filter by record type (A, CNAME, etc.)")
    list_parser.add_argument("--region", default="cn-hangzhou", help="Alidns region (default: cn-hangzhou)")

    # Add
    add_parser = subparsers.add_parser("add", help="Add a DNS record")
    add_parser.add_argument("--domain", required=True)
    add_parser.add_argument("--rr", required=True, help="Subdomain prefix (e.g., api, www, @)")
    add_parser.add_argument("--type", required=True, help="Record type (A, AAAA, CNAME, MX, TXT, etc.)")
    add_parser.add_argument("--value", required=True, help="Record value (IP, domain, text)")
    add_parser.add_argument("--ttl", type=int, default=600, help="TTL in seconds (default: 600)")
    add_parser.add_argument("--region", default="cn-hangzhou")

    # Update
    update_parser = subparsers.add_parser("update", help="Update a DNS record")
    update_parser.add_argument("--record-id", required=True, help="RecordId to update")
    update_parser.add_argument("--rr", required=True)
    update_parser.add_argument("--type", required=True)
    update_parser.add_argument("--value", required=True)
    update_parser.add_argument("--ttl", type=int, default=600)
    update_parser.add_argument("--region", default="cn-hangzhou")

    # Delete
    delete_parser = subparsers.add_parser("delete", help="Delete a DNS record")
    delete_parser.add_argument("--record-id", required=True, help="RecordId to delete")
    delete_parser.add_argument("--region", default="cn-hangzhou")

    # Enable / Disable
    enable_parser = subparsers.add_parser("enable", help="Enable a DNS record")
    enable_parser.add_argument("--record-id", required=True)
    enable_parser.add_argument("--region", default="cn-hangzhou")

    disable_parser = subparsers.add_parser("disable", help="Disable a DNS record")
    disable_parser.add_argument("--record-id", required=True)
    disable_parser.add_argument("--region", default="cn-hangzhou")

    args = parser.parse_args()

    if not args.action:
        parser.print_help()
        sys.exit(1)

    client = create_client(args.region)

    if args.action == "list":
        list_records(client, args.domain, rr=args.rr, record_type=getattr(args, "type", None))
    elif args.action == "add":
        add_record(client, args.domain, args.rr, args.type, args.value, args.ttl)
    elif args.action == "update":
        update_record(client, args.record_id, args.rr, args.type, args.value, args.ttl)
    elif args.action == "delete":
        delete_record(client, args.record_id)
    elif args.action == "enable":
        set_record_status(client, args.record_id, "Enable")
    elif args.action == "disable":
        set_record_status(client, args.record_id, "Disable")


if __name__ == "__main__":
    main()
