"""CSV import helpers for bulk lead onboarding."""

from __future__ import annotations

import csv
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any

from kiessclaw.models.contact import Contact
from kiessclaw.skills.prospect import ProspectSkill

_ALIASES: dict[str, tuple[str, ...]] = {
    "email": ("email", "email_address", "work_email", "e-mail", "email address"),
    "first_name": ("first_name", "first", "fname", "given_name", "first name"),
    "last_name": ("last_name", "last", "lname", "family_name", "surname", "last name"),
    "company": ("company", "company_name", "organization", "org"),
    "title": ("title", "job_title", "position", "role"),
    "domain": ("domain", "website", "company_domain", "url"),
}


@dataclass(slots=True)
class ImportResult:
    """Structured outcome for a CSV import attempt."""

    contacts_added: int = 0
    contacts_skipped: int = 0
    qualified: list[Contact] = field(default_factory=list)
    errors: list[str] = field(default_factory=list)
    filepath: str = ""
    contacts: list[Contact] = field(default_factory=list)

    def to_dict(self) -> dict[str, Any]:
        """Return JSON-serializable payload."""
        return {
            "contacts_added": self.contacts_added,
            "contacts_skipped": self.contacts_skipped,
            "qualified": [contact.to_dict() for contact in self.qualified],
            "errors": list(self.errors),
            "filepath": self.filepath,
        }


def import_contacts_csv(
    filepath: str,
    column_map: dict[str, str] | None = None,
    icp_score_min: int = 0,
    deduplicate: bool = True,
    existing_emails: set[str] | None = None,
) -> ImportResult:
    """Import contacts from CSV with alias auto-detection and deterministic scoring."""
    result = ImportResult(filepath=filepath)
    path = Path(filepath)
    if not path.exists():
        result.errors.append(f"File not found: {filepath}")
        return result

    try:
        with path.open(newline="", encoding="utf-8-sig") as handle:
            reader = csv.DictReader(handle)
            if not reader.fieldnames:
                result.errors.append("CSV has no header row")
                return result

            mapping = _resolve_column_map(reader.fieldnames, column_map or {})
            if "email" not in mapping:
                result.errors.append("Missing required email column")
                return result

            seen_emails: set[str] = {item.lower() for item in (existing_emails or set())}
            scorer = ProspectSkill({"agents": {"KPRO": {"settings": {"min_icp_score": icp_score_min}}}})
            for row_idx, row in enumerate(reader, start=2):
                parsed = _parse_row(row, mapping)
                email = parsed.get("email", "").lower()
                if not email:
                    result.contacts_skipped += 1
                    result.errors.append(f"Row {row_idx}: missing email")
                    continue
                validation = scorer.validate_email(email)
                # Keep strict format checks, but allow clearly-labeled demo/test domains
                # so sample datasets and documentation flows still import deterministically.
                if not validation["valid"] and validation.get("reason") == "invalid_format":
                    result.contacts_skipped += 1
                    result.errors.append(f"Row {row_idx}: invalid email ({validation['reason']})")
                    continue
                if deduplicate and email in seen_emails:
                    result.contacts_skipped += 1
                    continue
                seen_emails.add(email)

                scoring = scorer.score_icp_fit(
                    {
                        "title": parsed.get("title"),
                        "industry": parsed.get("industry"),
                        "employee_count": parsed.get("employee_count"),
                        "email": email,
                    }
                )
                contact = Contact(
                    email=email,
                    first_name=parsed.get("first_name", ""),
                    last_name=parsed.get("last_name", ""),
                    title=parsed.get("title") or None,
                    icp_score=int(scoring.get("score", 0)),
                )
                contact.enrichment_data = {
                    "company": parsed.get("company", ""),
                    "domain": parsed.get("domain", ""),
                }
                result.contacts.append(contact)
                result.contacts_added += 1
                if contact.icp_score >= icp_score_min:
                    result.qualified.append(contact)
    except Exception as exc:  # noqa: BLE001
        result.errors.append(str(exc))

    return result


def _resolve_column_map(headers: list[str], column_map: dict[str, str]) -> dict[str, str]:
    """Resolve canonical column names to actual CSV headers."""
    normalized_headers = {header.strip().lower(): header for header in headers}
    mapping: dict[str, str] = {}

    for canonical, source in column_map.items():
        wanted = source.strip().lower()
        if wanted in normalized_headers:
            mapping[canonical.strip().lower()] = normalized_headers[wanted]

    for canonical, aliases in _ALIASES.items():
        if canonical in mapping:
            continue
        for alias in aliases:
            key = alias.strip().lower()
            if key in normalized_headers:
                mapping[canonical] = normalized_headers[key]
                break
    return mapping


def _parse_row(row: dict[str, Any], mapping: dict[str, str]) -> dict[str, Any]:
    """Parse one CSV row into canonical fields."""
    parsed: dict[str, Any] = {}
    for canonical, source_header in mapping.items():
        value = row.get(source_header, "")
        parsed[canonical] = str(value).strip() if value is not None else ""
    domain = parsed.get("domain", "")
    email = parsed.get("email", "")
    if not domain and "@" in email:
        parsed["domain"] = email.split("@", 1)[1]
    if parsed.get("domain", "").startswith(("http://", "https://")):
        parsed["domain"] = parsed["domain"].split("//", 1)[1].split("/", 1)[0].lower()
    return parsed
