"""Deterministic sheet classification for Gremlin Triage."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any
import re

# Salesforce ID prefix mapping
SFDC_ID_PREFIXES = {
    "001": "Account",
    "003": "Contact",
    "00Q": "Lead",
    "006": "Opportunity",
    "00U": "Event",
    "00T": "Task",
    "005": "User",
    "01I": "Campaign Member",
}

# Common B2C email domains (use your existing list if available)
B2C_DOMAINS = {
    "gmail.com",
    "yahoo.com",
    "hotmail.com",
    "outlook.com",
    "aol.com",
    "icloud.com",
    "mail.com",
    "protonmail.com",
    "ymail.com",
    "live.com",
    "msn.com",
    "comcast.net",
    "att.net",
    "verizon.net",
    "me.com",
    # Extend as needed with existing B2C list
}

# Header patterns for classification
HEADER_PATTERNS = {
    "email": re.compile(r"^(email|e-mail|email.address|contact.email)$", re.I),
    "name": re.compile(r"^(name|full.?name|contact.?name|first.?name|last.?name)$", re.I),
    "company": re.compile(r"^(company|company.?name|organization|org|account.?name|business)$", re.I),
    "title": re.compile(r"^(title|job.?title|role|position)$", re.I),
    "phone": re.compile(r"^(phone|telephone|mobile|cell|phone.?number)$", re.I),
    "domain": re.compile(r"^(domain|website|web|url|company.?domain)$", re.I),
    "account_id": re.compile(r"^(account.?id|sfdc.?account.?id|salesforce.?account)$", re.I),
    "lead_id": re.compile(r"^(lead.?id|sfdc.?lead.?id)$", re.I),
    "contact_id": re.compile(r"^(contact.?id|sfdc.?contact.?id)$", re.I),
}


@dataclass
class TriageSummary:
    """Deterministic classification results."""

    row_count: int
    column_count: int
    headers: list[str]

    # Formula analysis
    has_formulas: bool = False
    formula_count: int = 0
    formula_density: float = 0.0
    has_offset_formulas: bool = False
    has_cross_sheet_refs: bool = False
    cross_sheet_tabs: list[str] = field(default_factory=list)

    # SFDC detection
    has_sfdc_ids: bool = False
    sfdc_id_types: list[str] = field(default_factory=list)
    sfdc_id_columns: list[str] = field(default_factory=list)

    # Column detection
    email_columns: list[str] = field(default_factory=list)
    domain_columns: list[str] = field(default_factory=list)
    name_columns: list[str] = field(default_factory=list)
    company_columns: list[str] = field(default_factory=list)

    # Data quality metrics
    b2c_email_pct: float = 0.0
    duplicate_email_pct: float = 0.0
    null_counts: dict[str, int] = field(default_factory=dict)

    # Classification
    likely_record_type: str = "unknown"  # event_leads, accounts, contacts, opps, model, unknown
    classification_confidence: str = "low"  # high, medium, low
    likely_use_cases: list[str] = field(default_factory=list)


def classify_sheet(
    values: list[list[Any]],
    formulas: list[list[str]] | None = None,
) -> TriageSummary:
    """
    Classify a sheet based on headers, data patterns, and formula structure.
    """
    if not values or not values[0]:
        return TriageSummary(row_count=0, column_count=0, headers=[])

    headers = [str(h).strip() for h in values[0]]
    data_rows = values[1:] if len(values) > 1 else []

    summary = TriageSummary(
        row_count=len(data_rows),
        column_count=len(headers),
        headers=headers,
    )

    # Detect column types from headers
    summary.email_columns = _detect_columns(headers, HEADER_PATTERNS["email"])
    summary.name_columns = _detect_columns(headers, HEADER_PATTERNS["name"])
    summary.company_columns = _detect_columns(headers, HEADER_PATTERNS["company"])
    summary.domain_columns = _detect_columns(headers, HEADER_PATTERNS["domain"])

    # Analyze formulas if provided
    if formulas:
        summary = _analyze_formulas(summary, formulas)

    # Analyze data patterns
    summary = _analyze_data(summary, headers, data_rows)

    # Determine likely record type and use cases
    summary = _classify_record_type(summary)
    summary = _determine_use_cases(summary)

    return summary


def _detect_columns(headers: list[str], pattern: re.Pattern) -> list[str]:
    """Find columns matching a header pattern."""
    return [h for h in headers if pattern.match(h.replace(" ", ".").replace("_", "."))]


def _analyze_formulas(summary: TriageSummary, formulas: list[list[str]]) -> TriageSummary:
    """Analyze formula patterns."""
    formula_count = 0
    has_offset = False
    has_cross_sheet = False
    cross_sheet_tabs = set()

    for row in formulas:
        for cell in row:
            if cell and str(cell).startswith("="):
                formula_count += 1
                cell_str = str(cell).upper()

                if "OFFSET" in cell_str:
                    has_offset = True

                # Detect cross-sheet references (contains '!')
                if "!" in cell_str:
                    has_cross_sheet = True
                    # Extract sheet name (handles quoted and unquoted)
                    matches = re.findall(r"'([^']+)'!|([A-Za-z0-9_]+)!", cell_str)
                    for match in matches:
                        tab = match[0] or match[1]
                        if tab:
                            cross_sheet_tabs.add(tab)

    total_cells = summary.row_count * summary.column_count

    summary.has_formulas = formula_count > 0
    summary.formula_count = formula_count
    summary.formula_density = formula_count / max(total_cells, 1)
    summary.has_offset_formulas = has_offset
    summary.has_cross_sheet_refs = has_cross_sheet
    summary.cross_sheet_tabs = list(cross_sheet_tabs)

    return summary


def _analyze_data(
    summary: TriageSummary,
    headers: list[str],
    data_rows: list[list[Any]],
) -> TriageSummary:
    """Analyze data patterns for SFDC IDs, B2C emails, duplicates, nulls."""
    if not data_rows:
        return summary

    # Build column index mapping
    col_indices = {h: i for i, h in enumerate(headers)}

    # Collect emails for B2C and duplicate analysis
    all_emails = []
    email_col_idx = None
    if summary.email_columns:
        email_col_idx = col_indices.get(summary.email_columns[0])

    # Detect SFDC IDs and collect metrics
    sfdc_id_types = set()
    sfdc_id_columns: list[str] = []
    null_counts = {h: 0 for h in headers}

    for row in data_rows:
        for col_idx, cell in enumerate(row):
            if col_idx >= len(headers):
                continue

            header = headers[col_idx]
            cell_str = str(cell).strip() if cell else ""

            # Check for nulls
            if not cell_str or cell_str.lower() in ("", "null", "none", "n/a"):
                null_counts[header] += 1
                continue

            # Check for SFDC ID patterns (15 or 18 char alphanumeric starting with known prefix)
            if len(cell_str) in (15, 18) and cell_str[:3] in SFDC_ID_PREFIXES:
                sfdc_type = SFDC_ID_PREFIXES[cell_str[:3]]
                sfdc_id_types.add(sfdc_type)
                if header not in sfdc_id_columns:
                    sfdc_id_columns.append(header)

            # Collect emails
            if col_idx == email_col_idx and "@" in cell_str:
                all_emails.append(cell_str.lower())

    # Calculate B2C percentage
    b2c_count = 0
    for email in all_emails:
        domain = email.split("@")[-1] if "@" in email else ""
        if domain in B2C_DOMAINS:
            b2c_count += 1

    b2c_pct = b2c_count / max(len(all_emails), 1)

    # Calculate duplicate email percentage
    unique_emails = set(all_emails)
    duplicate_count = len(all_emails) - len(unique_emails)
    duplicate_pct = duplicate_count / max(len(all_emails), 1)

    # Update summary
    summary.has_sfdc_ids = len(sfdc_id_types) > 0
    summary.sfdc_id_types = list(sfdc_id_types)
    summary.sfdc_id_columns = sfdc_id_columns
    summary.b2c_email_pct = round(b2c_pct, 3)
    summary.duplicate_email_pct = round(duplicate_pct, 3)
    summary.null_counts = {k: v for k, v in null_counts.items() if v > 0}

    return summary


def _classify_record_type(summary: TriageSummary) -> TriageSummary:
    """Determine the likely record type based on signals."""

    # Model detection: high formula density, OFFSET patterns, cross-sheet refs
    if _is_likely_model(summary):
        summary.likely_record_type = "model"
        summary.classification_confidence = "high" if summary.has_offset_formulas else "medium"
        return summary

    # SFDC export detection
    if summary.has_sfdc_ids:
        if "Account" in summary.sfdc_id_types:
            summary.likely_record_type = "accounts"
            summary.classification_confidence = "high"
        elif "Contact" in summary.sfdc_id_types:
            summary.likely_record_type = "contacts"
            summary.classification_confidence = "high"
        elif "Lead" in summary.sfdc_id_types:
            summary.likely_record_type = "leads"
            summary.classification_confidence = "high"
        elif "Opportunity" in summary.sfdc_id_types:
            summary.likely_record_type = "opps"
            summary.classification_confidence = "high"
        else:
            summary.likely_record_type = "sfdc_export"
            summary.classification_confidence = "medium"
        return summary

    # Event leads: has email + company/name columns, no SFDC IDs
    has_contact_info = bool(summary.email_columns or summary.name_columns)
    has_company_info = bool(summary.company_columns or summary.domain_columns)

    if has_contact_info and has_company_info and not summary.has_sfdc_ids:
        summary.likely_record_type = "event_leads"
        summary.classification_confidence = "high" if summary.email_columns else "medium"
        return summary

    # Account list without SFDC IDs
    if summary.company_columns and not has_contact_info:
        summary.likely_record_type = "account_list"
        summary.classification_confidence = "medium"
        return summary

    # Unknown
    summary.likely_record_type = "unknown"
    summary.classification_confidence = "low"
    return summary


def _is_likely_model(summary: TriageSummary) -> bool:
    """Determine if this is a financial/planning model vs data table."""
    # Strong signals for model
    if summary.has_offset_formulas:
        return True

    if summary.has_cross_sheet_refs and summary.formula_count > 50:
        return True

    # High formula density suggests model
    if summary.formula_density > 0.3:
        return True

    # Low row count + formulas = likely model
    if summary.row_count < 100 and summary.formula_count > 20:
        return True

    return False


def _determine_use_cases(summary: TriageSummary) -> TriageSummary:
    """Determine likely use cases based on record type and data quality."""
    use_cases: list[str] = []

    record_type = summary.likely_record_type

    if record_type == "model":
        use_cases = ["scan_model", "fix_safe", "explain_model"]

    elif record_type == "event_leads":
        use_cases = ["clean_dedupe", "match_accounts", "sfdc_enrich", "prepare_import"]

    elif record_type in ("accounts", "account_list"):
        use_cases = ["data_quality", "dedupe", "sfdc_enrich", "match_accounts"]

    elif record_type in ("contacts", "leads"):
        use_cases = ["data_quality", "dedupe", "sfdc_enrich"]

    elif record_type == "opps":
        use_cases = ["data_quality", "sfdc_enrich"]

    elif record_type == "sfdc_export":
        use_cases = ["data_quality", "dedupe", "sfdc_enrich"]

    else:  # unknown
        # Offer generic options based on what we found
        if summary.has_formulas:
            use_cases.append("scan_model")
        if summary.email_columns:
            use_cases.append("clean_dedupe")
            use_cases.append("match_accounts")
        if not use_cases:
            use_cases = ["data_quality", "scan_model"]

    summary.likely_use_cases = use_cases
    return summary


def build_suggested_actions(summary: TriageSummary) -> list[dict]:
    """Build suggested actions list from use cases."""

    ACTION_DEFINITIONS = {
        "scan_model": {
            "id": "scan_model",
            "label": "Scan Model for Issues",
            "description": "Check formula health, find broken references and pattern anomalies.",
            "icon": "search",
            "requires_tier": "free",
        },
        "fix_safe": {
            "id": "fix_safe",
            "label": "Fix Safe Issues",
            "description": "Auto-fix high-confidence issues like unquoted sheet references.",
            "icon": "wrench",
            "requires_tier": "pro",
        },
        "explain_model": {
            "id": "explain_model",
            "label": "Explain This Model",
            "description": "Generate plain-English documentation of how this model works.",
            "icon": "book",
            "requires_tier": "scale",
        },
        "clean_dedupe": {
            "id": "clean_dedupe",
            "label": "Clean & Dedupe This List",
            "description": "Remove duplicates and filter out consumer email domains.",
            "icon": "broom",
            "requires_tier": "free",
        },
        "match_accounts": {
            "id": "match_accounts",
            "label": "Match to Salesforce Accounts",
            "description": "Find which rows match existing Accounts in Salesforce.",
            "icon": "link",
            "requires_tier": "free",
        },
        "sfdc_enrich": {
            "id": "sfdc_enrich",
            "label": "Enrich from Salesforce",
            "description": "Add Account Owner, Industry, Tier and other fields from Salesforce.",
            "icon": "plus",
            "requires_tier": "pro",
        },
        "prepare_import": {
            "id": "prepare_import",
            "label": "Prepare for Salesforce Import",
            "description": "Validate required fields and normalize data for safe import.",
            "icon": "upload",
            "requires_tier": "pro",
        },
        "data_quality": {
            "id": "data_quality",
            "label": "Run Data Quality Check",
            "description": "Analyze completeness, validity, and identify data issues.",
            "icon": "chart",
            "requires_tier": "free",
        },
        "dedupe": {
            "id": "dedupe",
            "label": "Find Duplicates",
            "description": "Identify duplicate records by name, email, or domain.",
            "icon": "copy",
            "requires_tier": "free",
        },
    }

    actions = []
    for use_case in summary.likely_use_cases:
        if use_case in ACTION_DEFINITIONS:
            actions.append(ACTION_DEFINITIONS[use_case])

    # Limit to 4 actions max
    return actions[:4]
