"""
Dedupe policy models for object-specific duplicate detection rules.
"""

from typing import Optional, Dict, Any, List
from sqlalchemy import Column, JSON as SQLJSON, DateTime
from sqlmodel import Field
from datetime import datetime
from fmatch.saas.db import Base
import uuid


class DedupePolicy(Base, table=True):
    """
    Per-object dedupe policies that define what constitutes a duplicate.
    These policies are the single source of truth for duplicate detection logic.
    """

    __tablename__ = "dedupe_policies"
    __table_args__ = {"extend_existing": True}

    id: str = Field(primary_key=True, default_factory=lambda: str(uuid.uuid4()))
    account_id: Optional[str] = Field(default=None)  # NULL for default policies
    object_type: str = Field(nullable=False)  # Lead, Contact, Account
    policy_version: str = Field(nullable=False)  # e.g., "2025-08-18.1"

    # Core configuration
    thresholds: Dict[str, float] = Field(
        sa_column=Column(SQLJSON),
        default_factory=lambda: {"suggest": 0.60, "auto_link": 0.95},
    )

    # Anchors: Strong signals that indicate duplicates
    # e.g., ["email_exact", {"phone_exact": {"if": "mobile_or_rare", "max_freq": 2}}]
    anchors: List[Any] = Field(sa_column=Column(SQLJSON), default_factory=list)

    # Blockers: Fields to group records by for comparison
    # e.g., ["email", {"phone_rare": {"max_freq": 2}}, "linkedin"]
    blockers: List[Any] = Field(sa_column=Column(SQLJSON), default_factory=list)

    # Hard negatives: Conditions that prevent matches
    # e.g., ["company_only", "diff_email_without_strong_phone"]
    hard_negatives: List[Any] = Field(sa_column=Column(SQLJSON), default_factory=list)

    # Heuristics and domain knowledge
    # e.g., {"free_domains": ["gmail.com"], "office_phone_patterns": ["000$", "111$"]}
    heuristics: Optional[Dict[str, Any]] = Field(
        sa_column=Column(SQLJSON), default=None
    )

    # Metadata
    is_active: bool = Field(default=True)
    created_at: datetime = Field(sa_column=Column(DateTime, default=datetime.utcnow))
    updated_at: Optional[datetime] = Field(
        sa_column=Column(DateTime, onupdate=datetime.utcnow), default=None
    )
    last_run_at: Optional[datetime] = Field(
        default=None
    )  # Track when dedupe was last run
    created_by: Optional[str] = Field(default=None)
    notes: Optional[str] = Field(default=None)


# Default policies as Python dicts (will be inserted into DB)
DEFAULT_POLICIES = {
    "Lead": {
        "policy_version": "2025-08-18.1",
        "thresholds": {"suggest": 0.60, "auto_link": 0.95},
        "anchors": [
            "email_exact",
            {"phone_exact": {"if": "mobile_or_rare", "max_freq": 2}},
            "linkedin_exact",
            "external_id_exact",
            "vendor_lead_id_exact",
        ],
        "blockers": [
            "email",
            {"phone_rare": {"max_freq": 2}},
            "linkedin",
            "external_id",
            "vendor_lead_id",
        ],
        "hard_negatives": [
            "company_only",
            "diff_email_without_strong_phone",
            {"huge_domain_requires_second_anchor": {"max_domain_freq": 100}},
            "same_company_diff_contact",
        ],
        "heuristics": {
            "free_domains": [
                "gmail.com",
                "googlemail.com",
                "yahoo.com",
                "outlook.com",
                "hotmail.com",
                "icloud.com",
                "aol.com",
                "mail.com",
                "protonmail.com",
            ],
            "office_phone_patterns": ["000$", "111$", "100$", "^1800", "^1300"],
            "mobile_detection": {
                "prefer_mobile_field": True,
                "reject_extensions": True,
                "min_digits": 10,
            },
        },
    },
    "Contact": {
        "policy_version": "2025-08-18.1",
        "thresholds": {"suggest": 0.60, "auto_link": 0.90},
        "anchors": [
            "email_exact",
            {"phone_exact": {"if": "mobile_or_rare", "max_freq": 2}},
            "linkedin_exact",
            "external_id_exact",
            {"account_name": {"name_similarity": 0.92}},
        ],
        "blockers": [
            "email",
            {"phone_rare": {"max_freq": 2}},
            "linkedin",
            "external_id",
            "account_lastname",
        ],
        "hard_negatives": [
            "diff_email_without_strong_phone",
            {"huge_domain_requires_second_anchor": {"max_domain_freq": 100}},
            "diff_account_weak_name",
        ],
        "heuristics": {
            "free_domains": [
                "gmail.com",
                "googlemail.com",
                "yahoo.com",
                "outlook.com",
                "hotmail.com",
                "icloud.com",
                "aol.com",
            ],
            "office_phone_patterns": ["000$", "111$", "100$"],
            "name_similarity_threshold": 0.92,
        },
    },
    "Account": {
        "policy_version": "2025-08-18.1",
        "thresholds": {"suggest": 0.70, "auto_link": 0.95},
        "anchors": [
            {"website_name": {"name_similarity": 0.70, "exclude_free": True}},
            "registration_id_exact",
            {"phone_name": {"name_similarity": 0.80}},
        ],
        "blockers": ["website_domain", "registration_id", "phone"],
        "hard_negatives": [
            "domain_only_if_common",
            {"huge_domain_requires_name": {"max_domain_freq": 500}},
            "weak_name_similarity",
        ],
        "heuristics": {
            "free_domains": ["gmail.com", "yahoo.com", "outlook.com"],
            "registration_fields": ["EIN__c", "ABN__c", "VAT__c"],
            "name_similarity_threshold": 0.70,
        },
    },
}
