"""
Technical / integration configuration owned by System Administration.

Credentials for third-party technical integrations (M-Pesa Daraja today; room
for more) are administered here, not inside the operational modules that consume
them. The underlying records live in their owning app (e.g. the finance
`MpesaApiConfig`, which carries a GL-account FK), but they are read/written only
through these System-Administration helpers and endpoints.

Secrets are never returned to the client — only a boolean indicating whether a
value is set. Updates leave a secret untouched when the field is blank.
"""
from __future__ import annotations


def get_or_create_mpesa_config(company_branch):
    from finance_and_accounting.models import MpesaApiConfig

    cfg, _created = MpesaApiConfig.objects.get_or_create(company_branch=company_branch)
    return cfg


def get_or_create_crm_integration(company_profile):
    from system_administration.models import CompanyIntegrationSettings

    obj, _created = CompanyIntegrationSettings.objects.get_or_create(
        company_profile=company_profile)
    return obj


def crm_integration_to_map(obj) -> dict:
    return {
        "crm_performance_webhook_url": obj.crm_performance_webhook_url or "",
        "crm_stock_webhook_url": obj.crm_stock_webhook_url or "",
        "crm_quotation_webhook_url": obj.crm_quotation_webhook_url or "",
        "crm_webhook_secret_set": bool(obj.crm_webhook_secret),
        "crm_webhook_active": obj.crm_webhook_active,
        "erp_ui_public_url": obj.erp_ui_public_url or "",
        "erp_api_public_url": obj.erp_api_public_url or "",
        "allowed_hosts": obj.allowed_hosts or "",
    }


def apply_crm_integration_update(obj, data):
    if "crm_performance_webhook_url" in data:
        obj.crm_performance_webhook_url = (data.get("crm_performance_webhook_url") or "").strip()
    if "crm_stock_webhook_url" in data:
        obj.crm_stock_webhook_url = (data.get("crm_stock_webhook_url") or "").strip()
    if "crm_quotation_webhook_url" in data:
        obj.crm_quotation_webhook_url = (data.get("crm_quotation_webhook_url") or "").strip()
    if "erp_ui_public_url" in data:
        obj.erp_ui_public_url = (data.get("erp_ui_public_url") or "").strip().rstrip('/')
    if "erp_api_public_url" in data:
        obj.erp_api_public_url = (data.get("erp_api_public_url") or "").strip().rstrip('/')
    if data.get("crm_webhook_secret"):
        obj.crm_webhook_secret = data["crm_webhook_secret"]
    if "crm_webhook_active" in data:
        obj.crm_webhook_active = str(data.get("crm_webhook_active")).lower() in ("true", "1", "yes", "on")

    from system_administration.host_policy import clear_allowed_hosts_cache, compute_allowed_hosts

    extra_csv = (data.get("allowed_hosts") or "").strip() if "allowed_hosts" in data else ""
    obj.allowed_hosts = compute_allowed_hosts(
        obj.erp_ui_public_url,
        obj.erp_api_public_url,
        extra_csv,
    )
    obj.save()
    clear_allowed_hosts_cache()
    return obj


def mpesa_config_to_map(cfg) -> dict:
    return {
        "environment": cfg.environment,
        "consumer_key": cfg.consumer_key or "",
        "consumer_secret_set": bool(cfg.consumer_secret),
        "short_code": cfg.short_code or "",
        "pass_key_set": bool(cfg.pass_key),
        "initiator_name": cfg.initiator_name or "",
        "mpesa_account_id": str(cfg.mpesa_account_id or ""),
        "is_active": cfg.is_active,
        "last_synced_on": cfg.last_synced_on.isoformat() if cfg.last_synced_on else "",
    }


def branch_gl_account_options(company_branch) -> list[dict]:
    """Bank/cash GL accounts the M-Pesa wallet can map to (for the admin picker)."""
    from finance_and_accounting.models import ChartOfAccount

    accounts = ChartOfAccount.objects.filter(
        company_branch=company_branch,
        recycle_bin=False,
        is_active=True,
    ).select_related("account_type").order_by("account_number")

    options = []
    for acc in accounts:
        type_key = acc.account_type.type_key if acc.account_type else ""
        # Prefer cash/bank accounts but keep the list usable if none are typed.
        options.append({
            "account_id": str(acc.id),
            "account_name": acc.account_name,
            "account_number": acc.account_number,
            "is_cash_or_bank": type_key in {"bank", "cash_and_cash_equivalents"},
        })
    cash_first = [o for o in options if o["is_cash_or_bank"]]
    return cash_first or options


def apply_mpesa_config_update(cfg, data, staff_profile):
    from finance_and_accounting.models import ChartOfAccount

    if "environment" in data:
        cfg.environment = data.get("environment") or "sandbox"
    if "consumer_key" in data:
        cfg.consumer_key = data.get("consumer_key") or ""
    if "short_code" in data:
        cfg.short_code = data.get("short_code") or ""
    if "initiator_name" in data:
        cfg.initiator_name = data.get("initiator_name") or ""
    if "is_active" in data:
        cfg.is_active = str(data.get("is_active")).lower() in ("true", "1", "yes", "on")

    # Secrets: only overwrite when a non-blank value is supplied.
    if data.get("consumer_secret"):
        cfg.consumer_secret = data["consumer_secret"]
    if data.get("pass_key"):
        cfg.pass_key = data["pass_key"]

    if data.get("mpesa_account_id"):
        cfg.mpesa_account = ChartOfAccount.objects.get(id=data["mpesa_account_id"])
    elif "mpesa_account_id" in data and not data.get("mpesa_account_id"):
        cfg.mpesa_account = None

    cfg.updated_by = staff_profile
    cfg.save()
    return cfg
