"""Validation and name-derivation helpers for FullEnrich."""

from __future__ import annotations

import re
from typing import Any, Dict, Iterable, Optional, Tuple
from urllib.parse import urlparse


_SUFFIXES = {"jr", "sr", "ii", "iii", "iv", "v", "phd", "md", "esq"}


def is_valid_contact_input(
    email: Optional[str],
    linkedin_url: Optional[str],
    *,
    first_name: Optional[str] = None,
    last_name: Optional[str] = None,
    firstname: Optional[str] = None,
    lastname: Optional[str] = None,
    domain: Optional[str] = None,
    company_name: Optional[str] = None,
) -> bool:
    email_val = str(email).strip() if email is not None else ""
    if email_val and "@" in email_val:
        return True
    linkedin_val = str(linkedin_url).strip() if linkedin_url is not None else ""
    if linkedin_val:
        return True
    first = first_name if first_name is not None else firstname
    last = last_name if last_name is not None else lastname
    if first and last and (domain or company_name):
        return True
    return False


def extract_domain_from_email(email: Optional[str]) -> Optional[str]:
    if not email or "@" not in email:
        return None
    domain = email.split("@", 1)[1].strip().lower()
    return domain or None


def extract_custom_value(custom: Dict[str, Any], keys: Iterable[str]) -> Optional[str]:
    if not custom:
        return None
    lowered = {str(k).strip().lower(): v for k, v in custom.items()}
    for key in keys:
        val = lowered.get(str(key).strip().lower())
        if val is not None and str(val).strip():
            return str(val).strip()
    return None


def _normalize_name(value: str) -> str:
    clean = re.sub(r"\s+", " ", str(value or "").strip())
    return clean


def split_fullname(value: str) -> Tuple[str, str]:
    value = _normalize_name(value)
    if not value:
        return "", ""
    if "," in value:
        last, first = [p.strip() for p in value.split(",", 1)]
        return first.title(), last.title()
    parts = value.split(" ")
    if parts and parts[-1].lower().strip(".") in _SUFFIXES:
        parts = parts[:-1]
    if len(parts) == 1:
        return parts[0].title(), ""
    return parts[0].title(), parts[-1].title()


def _name_from_linkedin(linkedin_url: Optional[str]) -> Optional[Tuple[str, str]]:
    if not linkedin_url:
        return None
    url = str(linkedin_url).strip()
    if not url:
        return None
    if "://" not in url:
        url = "https://" + url
    parsed = urlparse(url)
    path = parsed.path or ""
    segments = [seg for seg in path.split("/") if seg]
    if not segments:
        return None
    if segments[0].lower() in {"in", "pub"} and len(segments) > 1:
        slug = segments[1]
    else:
        slug = segments[-1]
    slug = slug.replace("-", " ").replace("_", " ")
    slug = re.sub(r"\d+", " ", slug)
    slug = re.sub(r"\s+", " ", slug).strip()
    if not slug:
        return None
    first, last = split_fullname(slug)
    if not first:
        return None
    return first, last or "Unknown"


def _name_from_email(email: Optional[str]) -> Optional[Tuple[str, str]]:
    if not email:
        return None
    local = str(email).split("@", 1)[0].strip()
    if not local:
        return None
    local = re.sub(r"[._+\-]+", " ", local)
    local = re.sub(r"\d+", " ", local)
    local = re.sub(r"\s+", " ", local).strip()
    if not local:
        return None
    first, last = split_fullname(local)
    if not first:
        return None
    return first, last or "Unknown"


def _name_from_custom(custom: Dict[str, Any]) -> Optional[Tuple[str, str]]:
    if not custom:
        return None
    first = extract_custom_value(custom, ["first_name", "firstname", "first name"])
    last = extract_custom_value(custom, ["last_name", "lastname", "last name"])
    if first or last:
        first_val = (first or "").strip()
        last_val = (last or "").strip()
        if first_val and not last_val:
            last_val = "Unknown"
        if first_val:
            return first_val.title(), last_val.title() if last_val else "Unknown"
    full = extract_custom_value(custom, ["full_name", "full name", "name"])
    if full:
        first_val, last_val = split_fullname(full)
        if first_val:
            return first_val, last_val or "Unknown"
    return None


def derive_contact_name(
    first_name: Optional[str] = None,
    last_name: Optional[str] = None,
    *,
    email: Optional[str] = None,
    linkedin_url: Optional[str] = None,
    custom: Optional[Dict[str, Any]] = None,
) -> Optional[Tuple[str, str]]:
    if first_name or last_name:
        first_val = (first_name or "").strip()
        last_val = (last_name or "").strip()
        if first_val and not last_val:
            last_val = "Unknown"
        if first_val:
            return first_val.title(), last_val.title() if last_val else "Unknown"
    custom_name = _name_from_custom(custom or {})
    if custom_name:
        return custom_name
    linkedin_name = _name_from_linkedin(linkedin_url)
    if linkedin_name:
        return linkedin_name
    return _name_from_email(email)
