"""Detect data quality issues within rows or individual cells."""

from __future__ import annotations

import re
from collections import Counter
from typing import Any, Dict, List, Optional, Sequence, Tuple

from ._decorators import with_metrics

# Expanded test patterns
TEST_PATTERNS_RE = re.compile(
    r"(test[\s_]*(data|account|user|email|company)?|asdf+|qwerty|lorem\s*ipsum|dummy|fake|sample\s*(data|text)|foo\s*bar)",
    re.IGNORECASE,
)

PLACEHOLDER_VALUES = {
    "tbd",
    "tba",
    "n/a",
    "na",
    "none",
    "null",
    "nil",
    "placeholder",
    "sample",
    "xxx",
    "test",
    "unknown",
    "undefined",
    "blank",
    "-",
    "--",
    "pending",
    "todo",
    "fixme",
    "delete",
    "remove",
}

# Phone dummies - expanded list
FAKE_PHONES = {
    "5555555555",
    "5555551234",
    "5555551212",
    "5555550000",
    "1234567890",
    "0000000000",
    "1111111111",
    "9999999999",
    "0123456789",
    "9876543210",
}

# Precompiled patterns for performance
EMAIL_RE = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")
ALL_CAPS_RE = re.compile(r"^[A-Z0-9\s]+$")
PUNCTUATION_RE = re.compile(r"[!?.]{3,}")
EMOJI_RE = re.compile(
    r"[\U0001F600-\U0001F64F|\U0001F300-\U0001F5FF|\U0001F680-\U0001F6FF|"
    r"\U0001F1E0-\U0001F1FF|\U00002702-\U000027B0|\U000024C2-\U0001F251]+"
)
REPEATED_CHARS_RE = re.compile(r"(.)\1{4,}")  # 5+ repeated characters


def _normalize_headers(headers: Sequence[Any], length: int) -> List[str]:
    names: List[str] = []
    for idx in range(length):
        raw = "" if headers is None or idx >= len(headers) else headers[idx]
        label = str(raw).strip() if raw is not None else ""
        if not label:
            label = f"Column {idx + 1}"
        names.append(label)
    return names


def _strip(value: Any) -> str:
    return value.strip() if isinstance(value, str) else str(value or "")


def _digits(value: Any) -> str:
    return re.sub(r"\D", "", str(value or ""))


def _detect_issue(value: Any) -> Optional[str]:
    """Detect various data quality issues in a single value."""
    if value is None:
        return None
    text = _strip(value)
    if not text:
        return None

    lowered = text.lower()

    # Test data patterns
    if TEST_PATTERNS_RE.search(lowered):
        return "test_data"
    if lowered in PLACEHOLDER_VALUES:
        return "placeholder"

    # Phone validation
    digits = _digits(text)
    if digits:
        if digits in FAKE_PHONES:
            return "fake_phone"
        if len(digits) < 7 or len(digits) > 15:
            return "invalid_phone"
        if len(digits) in (10, 11) and digits[:3] == "555":
            return "fake_phone"  # 555 prefix is commonly fake

    # Email validation
    if "@" in text:
        if not EMAIL_RE.fullmatch(text):
            return "invalid_email"
        # Check for test email patterns
        if any(test in lowered for test in ["test@", "@test.", "@example.", "@fake."]):
            return "test_email"

    # Phone format check (if looks like phone)
    elif digits and 7 <= len(digits) <= 15:
        if len(digits) not in (10, 11, 7):  # Common valid lengths
            return "invalid_phone"

    # ALLCAPS detection
    if ALL_CAPS_RE.match(text) and len(text) > 4 and " " in text:
        return "suspicious_caps"

    # Emoji detection
    if EMOJI_RE.search(text):
        return "contains_emoji"

    # Excessive punctuation
    if PUNCTUATION_RE.search(text):
        return "suspicious_punctuation"

    # Repeated characters (like "aaaaaaa")
    if REPEATED_CHARS_RE.search(text):
        return "repeated_chars"

    return None


def _detect_row_issue(
    row: Sequence[Any], headers: Sequence[Any]
) -> Tuple[bool, str, Dict[str, Any]]:
    normalized_headers = _normalize_headers(headers, len(row))
    for idx, cell in enumerate(row):
        issue = _detect_issue(cell)
        if issue:
            header = normalized_headers[idx]
            return True, issue, {"field": header, "index": idx, "value": cell}
    return False, "", {}


@with_metrics
def detect_data_quality_issues(payload: Dict[str, Any]) -> Dict[str, Any]:
    """Detect data quality issues and return top issue types for dashboards."""
    if payload.get("is_header"):
        return {"value": [False, ""], "meta": {"reason": "header_row"}}

    if "row" in payload:
        row = payload.get("row") or []
        headers = payload.get("headers") or []

        # Collect all issues in the row
        issues_found = []
        for idx, cell in enumerate(row):
            issue = _detect_issue(cell)
            if issue:
                issues_found.append(issue)

        if issues_found:
            # Count issue types for dashboard metrics
            issue_counts = Counter(issues_found)
            top_issues = issue_counts.most_common(3)

            # Return the first issue found
            first_issue = issues_found[0]
            return {
                "value": [True, first_issue],
                "meta": {
                    "total_issues": len(issues_found),
                    "issue_types": dict(issue_counts),
                    "top_3_issues": [issue for issue, count in top_issues],
                    "checked_cells": len(row),
                },
            }

        return {
            "value": [False, ""],
            "meta": {"checked_cells": len(row), "issues_found": 0},
        }

    # Single value check
    issue = _detect_issue(payload.get("value"))
    if issue:
        return {
            "value": [True, issue],
            "meta": {"value": payload.get("value"), "issue_type": issue},
        }
    return {"value": [False, ""], "meta": {}}
