"""Field mapping utilities for CRM providers."""

from __future__ import annotations

from typing import Any, Dict, Iterable, List


DEFAULT_OBJECT_MAP: Dict[str, Dict[str, str]] = {
    "salesforce": {
        "opportunity": "Opportunity",
        "lead": "Lead",
        "contact": "Contact",
        "account": "Account",
        "task": "Task",
        "user": "User",
        "contract": "Contract",
        "group": "Group",
        "deal_history": "OpportunityFieldHistory",
    },
    "hubspot": {
        "opportunity": "deals",
        "lead": "contacts",
        "contact": "contacts",
        "account": "companies",
        "task": "tasks",
        "user": "owners",
        "contract": "unsupported",
        "group": "unsupported",
        "deal_history": "unsupported",
    },
    "dynamics": {
        "opportunity": "opportunity",
        "lead": "lead",
        "contact": "contact",
        "account": "account",
        "task": "task",
        "user": "systemuser",
        "contract": "contract",
        "group": "unsupported",
        "deal_history": "unsupported",
    },
}


DEFAULT_FIELD_MAP: Dict[str, Dict[str, Dict[str, Any]]] = {
    "hubspot": {
        "opportunity": {
            "Id": "hs_object_id",
            "Name": "dealname",
            "Amount": "amount",
            "StageName": "dealstage",
            "IsClosed": "hs_is_closed",
            "CloseDate": "closedate",
            "LastActivityDate": "notes_last_updated",
            "NextStep": "hs_next_step",
            "ForecastCategory": "hs_forecast_category",
            "Probability": "hs_deal_stage_probability",
            "OwnerId": "hubspot_owner_id",
            "CreatedDate": "createdate",
        },
        "lead": {
            "Id": "hs_object_id",
            "Name": "firstname",
            "Email": "email",
            "Phone": "phone",
            "MobilePhone": "mobilephone",
            "Company": "company",
            "IsConverted": "lifecyclestage",
            "Status": "hs_lead_status",
            "OwnerId": "hubspot_owner_id",
            "CreatedDate": "createdate",
            "LastActivityDate": "hs_lastmodifieddate",
            "lifecyclestage": "lifecyclestage",
            "lastname": "lastname",
        },
        "contact": {
            "Id": "hs_object_id",
            "Name": "firstname",
            "Email": "email",
            "Phone": "phone",
            "MobilePhone": "mobilephone",
            "Company": "company",
            "Status": "hs_lead_status",
            "OwnerId": "hubspot_owner_id",
            "CreatedDate": "createdate",
            "LastActivityDate": "hs_lastmodifieddate",
            "lastname": "lastname",
        },
        "account": {
            "Id": "hs_object_id",
            "Name": "name",
            "Website": "domain",
            "Industry": "industry",
            "NumberOfEmployees": "numberofemployees",
            "LastActivityDate": "hs_lastmodifieddate",
            "OwnerId": "hubspot_owner_id",
            "CreatedDate": "createdate",
        },
        "task": {
            "Id": "hs_object_id",
            "Subject": "hs_task_subject",
            "Status": "hs_task_status",
            "Priority": "hs_task_priority",
            "Body": "hs_task_body",
            "OwnerId": "hubspot_owner_id",
            "CreatedDate": "createdate",
        },
        "user": {
            "Id": "id",
            "IsActive": "archived",
            "Name": "email",
            "Email": "email",
        },
    },
    "dynamics": {
        "opportunity": {
            "Id": "opportunityid",
            "Name": "name",
            "Amount": "estimatedvalue",
            "StageName": "stepname",
            "IsClosed": "statecode",
            "CloseDate": "estimatedclosedate",
            "LastActivityDate": "modifiedon",
            "LastModifiedDate": "modifiedon",
            "NextStep": "stepname",
            "ForecastCategory": "forecastcategory",
            "Probability": "closeprobability",
            "OwnerId": "_ownerid_value",
            "CreatedDate": "createdon",
        },
        "lead": {
            "Id": "leadid",
            "Name": "fullname",
            "Email": "emailaddress1",
            "Phone": "telephone1",
            "Company": "companyname",
            "IsConverted": "statecode",
            "Status": "statuscode",
            "LastActivityDate": "modifiedon",
            "LastModifiedDate": "modifiedon",
            "OwnerId": "_ownerid_value",
            "CreatedDate": "createdon",
        },
        "contact": {
            "Id": "contactid",
            "Name": "fullname",
            "Email": "emailaddress1",
            "Phone": "telephone1",
            "Company": "parentcustomerid",
            "Status": "statuscode",
            "LastActivityDate": "modifiedon",
            "LastModifiedDate": "modifiedon",
            "OwnerId": "_ownerid_value",
            "CreatedDate": "createdon",
        },
        "account": {
            "Id": "accountid",
            "Name": "name",
            "Website": "websiteurl",
            "ParentId": "_parentaccountid_value",
            "Industry": "industrycode",
            "NumberOfEmployees": "numberofemployees",
            "LastActivityDate": "modifiedon",
            "LastModifiedDate": "modifiedon",
            "OwnerId": "_ownerid_value",
            "CreatedDate": "createdon",
        },
        "task": {
            "Id": "activityid",
            "Subject": "subject",
            "Status": "statuscode",
            "Priority": "prioritycode",
            "Body": "description",
            "RelatedToId": "_regardingobjectid_value",
            "OwnerId": "_ownerid_value",
            "CreatedDate": "createdon",
        },
        "user": {
            "Id": "systemuserid",
            "IsActive": "isdisabled",
            "Name": "fullname",
            "Email": "internalemailaddress",
        },
        "contract": {
            "Id": "contractid",
            "Name": "title",
            "Status": "statuscode",
            "RenewalDate": "expireson",
            "OwnerId": "_ownerid_value",
            "CreatedDate": "createdon",
        },
    },
}


class FieldMapper:
    def __init__(
        self,
        crm: str,
        overrides: Dict[str, Dict[str, Dict[str, str]]] | None = None,
    ) -> None:
        self.crm = crm
        self._object_map = dict(DEFAULT_OBJECT_MAP.get(crm, {}))
        self._field_map = {k: dict(v) for k, v in DEFAULT_FIELD_MAP.get(crm, {}).items()}
        if overrides:
            for obj, fields in overrides.items():
                key = str(obj).lower()
                existing = self._field_map.setdefault(key, {})
                existing.update(fields)

    def native_object(self, canonical_object: str) -> str | None:
        key = str(canonical_object)
        mapped = self._object_map.get(key)
        if mapped is None:
            mapped = self._object_map.get(key.lower())
        if mapped == "unsupported":
            return None
        return mapped or canonical_object

    def to_native_field(self, object_type: str, canonical_field: str) -> Any:
        mapping = self._field_map.get(str(object_type).lower(), {})
        return mapping.get(canonical_field, canonical_field)

    def to_native_fields(self, object_type: str, canonical_fields: Iterable[str]) -> List[str]:
        results: List[str] = []
        obj_key = str(object_type).lower()
        for field in canonical_fields:
            native = self.to_native_field(obj_key, field)
            if isinstance(native, list):
                for item in native:
                    if item not in results:
                        results.append(item)
            else:
                if native not in results:
                    results.append(str(native))
        return results

    def from_native_row(self, object_type: str, native_row: Dict[str, Any]) -> Dict[str, Any]:
        reverse_map = self._reverse_map(str(object_type).lower())
        canonical: Dict[str, Any] = {}
        for key, value in native_row.items():
            canon = reverse_map.get(key, key)
            canonical[canon] = value
        return canonical

    def _reverse_map(self, object_type: str) -> Dict[str, str]:
        reverse: Dict[str, str] = {}
        mapping = self._field_map.get(str(object_type).lower(), {})
        for canon, native in mapping.items():
            if isinstance(native, list):
                for item in native:
                    reverse[item] = canon
            else:
                reverse[str(native)] = canon
        return reverse


__all__ = ["FieldMapper", "DEFAULT_OBJECT_MAP", "DEFAULT_FIELD_MAP"]
