import logging
from datetime import date, datetime
from typing import Any, Dict, List, Optional
import xml.etree.ElementTree as ET
import httpx

from integrations.base import RegistrarBase

logger = logging.getLogger(__name__)


class NameSiloIntegration(RegistrarBase):
    """
    NameSilo XML API Integration.
    API docs: https://www.namesilo.com/api-reference
    Base URL: https://www.namesilo.com/api
    """

    BASE_URL = "https://www.namesilo.com/api"

    def __init__(self, credentials: Dict[str, Any]) -> None:
        self.api_key: str = credentials.get("api_key", "").strip()

    async def test_connection(self) -> bool:
        """Test API key by checking domain count."""
        if not self.api_key:
            raise ValueError("NameSilo API Key is required.")

        async with httpx.AsyncClient(timeout=15.0) as client:
            resp = await client.get(
                f"{self.BASE_URL}/getAccountBalance",
                params={"version": "1", "type": "xml", "key": self.api_key},
            )
            if resp.status_code == 200:
                root = ET.fromstring(resp.text)
                code = root.findtext(".//reply/code")
                if code == "300":
                    return True
                detail = root.findtext(".//reply/detail", "Authentication failed")
                raise ValueError(f"NameSilo error: {detail} (code {code})")
            raise ValueError(f"NameSilo HTTP error {resp.status_code}")

    async def list_domains(self) -> List[Dict[str, Any]]:
        """List all domains with expiry dates: GET /listDomains"""
        domains: List[Dict[str, Any]] = []
        async with httpx.AsyncClient(timeout=25.0) as client:
            resp = await client.get(
                f"{self.BASE_URL}/listDomains",
                params={"version": "1", "type": "xml", "key": self.api_key},
            )
            if resp.status_code != 200:
                logger.error(f"NameSilo listDomains failed: {resp.status_code} {resp.text}")
                return domains

            try:
                root = ET.fromstring(resp.text)
                for domain_elem in root.findall(".//domains/domain"):
                    domain_name = domain_elem.text or domain_elem.get("name")
                    if not domain_name:
                        continue

                    expiry_raw = domain_elem.get("expires")
                    expiry_date: Optional[date] = None
                    if expiry_raw:
                        try:
                            expiry_date = datetime.strptime(expiry_raw.strip(), "%Y-%m-%d").date()
                        except Exception:
                            pass

                    domains.append({
                        "domain_name": domain_name.lower().strip(),
                        "expiry_date": expiry_date,
                        "auto_renew": domain_elem.get("auto_renew", "No").lower() in ("yes", "1", "true"),
                        "status": domain_elem.get("status", "Active").lower(),
                        "registrar_domain_id": domain_name,
                    })
            except Exception as e:
                logger.error(f"Failed to parse NameSilo XML response: {e}")

        return domains

    async def get_dns_records(self, domain_name: str) -> List[Dict[str, Any]]:
        """Fetch DNS records from NameSilo: GET /dnsListRecords"""
        records: List[Dict[str, Any]] = []
        async with httpx.AsyncClient(timeout=15.0) as client:
            resp = await client.get(
                f"{self.BASE_URL}/dnsListRecords",
                params={
                    "version": "1",
                    "type": "xml",
                    "key": self.api_key,
                    "domain": domain_name.lower().strip(),
                },
            )
            if resp.status_code == 200:
                try:
                    root = ET.fromstring(resp.text)
                    for r in root.findall(".//resource_record"):
                        host = r.findtext("host", "@")
                        # Strip domain name suffix if present
                        clean_name = host.replace(f".{domain_name}", "").replace(domain_name, "@") or "@"
                        records.append({
                            "record_type": r.findtext("type", "A").upper(),
                            "name": clean_name,
                            "value": r.findtext("value", ""),
                            "ttl": int(r.findtext("ttl", "7207")),
                            "priority": int(r.findtext("distance")) if r.findtext("distance") else None,
                        })
                except Exception as e:
                    logger.warning(f"Failed to parse NameSilo DNS records: {e}")
        return records
