from __future__ import annotations

import hashlib
import json
import re
from datetime import date, datetime
from typing import Any, List, Optional


NULL_MARKERS = {"", "nan", "none", "null", "nat", "未填写", "暂无", "-"}


def clean_text(value: Any) -> str:
    if value is None:
        return ""
    text = str(value).strip()
    text = text.replace("\u3000", " ")
    text = re.sub(r"\s+", " ", text)
    return text


def is_blank(value: Any) -> bool:
    return clean_text(value).lower() in NULL_MARKERS


def normalize_optional_text(value: Any) -> Optional[str]:
    text = clean_text(value)
    if text.lower() in NULL_MARKERS:
        return None
    return text


def normalize_phone(value: Any) -> Optional[str]:
    text = clean_text(value)
    if not text:
        return None
    digits = re.sub(r"\D+", "", text)
    if len(digits) >= 11:
        return digits[-11:]
    if len(digits) >= 7:
        return digits
    return None


def normalize_date(value: Any) -> Optional[str]:
    text = clean_text(value)
    if not text or text.lower() in NULL_MARKERS:
        return None
    text = text.replace("年", ".").replace("月", ".").replace("日", "")
    text = text.replace("/", ".").replace("-", ".")
    text = re.sub(r"\.+", ".", text).strip(".")
    for fmt in ("%Y.%m.%d", "%Y.%m", "%m.%d"):
        try:
            parsed = datetime.strptime(text, fmt)
            year = parsed.year
            if fmt == "%m.%d":
                year = date.today().year
            day = parsed.day if "%d" in fmt else 1
            return date(year, parsed.month, day).isoformat()
        except ValueError:
            continue
    if re.fullmatch(r"\d{4}\.\d{1,2}\.\d{1,2}", text):
        parts = [int(item) for item in text.split(".")]
        return date(parts[0], parts[1], parts[2]).isoformat()
    return None


def normalize_tags(value: Any) -> List[str]:
    if isinstance(value, (list, tuple, set)):
        return [clean_text(item) for item in value if clean_text(item)]
    text = clean_text(value)
    if not text:
        return []
    parts = re.split(r"[,，、/\s]+", text)
    return [item for item in (part.strip() for part in parts) if item]


def guess_value_type(label: str, values: List[Any]) -> str:
    joined_label = clean_text(label).lower()
    if any(k in joined_label for k in ["电话", "手机", "mobile", "phone"]):
        return "phone"
    if any(k in joined_label for k in ["生日", "日期", "到期", "续费", "回访", "预约", "到期", "回访"]):
        return "date"
    non_blank = [clean_text(v) for v in values if not is_blank(v)]
    if non_blank and all(normalize_date(v) for v in non_blank):
        return "date"
    return "text"


def stable_field_key(label: str) -> str:
    text = clean_text(label).lower()
    ascii_text = re.sub(r"[^a-z0-9]+", "_", text).strip("_")
    if ascii_text:
        return ascii_text[:48]
    digest = hashlib.sha1(clean_text(label).encode("utf-8")).hexdigest()[:12]
    return "fld_{}".format(digest)
