"""Modèle Frappe/ERPNext v15 : structure native des fixtures Workflow.

Sépare la CONNAISSANCE FRAPPE (noms de DocTypes, champs de table enfant, valeurs
autorisées) de l'assemblage métier (`builder.py`). Contrainte #1 « ERPNext natif
= priorité absolue » : on n'invente aucun moteur de workflow externe — on
produit les DocTypes standard du moteur Workflow de Frappe.

DocTypes produits (references Frappe) :
  - `Workflow`               → le graphe (document_type + states[] + transitions[]).
  - `Workflow Document State`→ table enfant `states` : un état + son doc_status +
    le rôle qui peut éditer (`allow_edit`).
  - `Workflow Transition`    → table enfant `transitions` : arête état→action→état,
    gardée par un rôle (`allowed`) + `allow_self_approval`.
  - `Workflow State`         → DocType maître (nom d'état + `style` d'affichage).
  - `Workflow Action Master` → DocType maître (nom d'action).

Aucun accès VPS : chaque fonction renvoie un dict sérialisable.
"""

from __future__ import annotations

from typing import Any

# doc_status Frappe natifs. Le long d'une transition, doc_status est MONOTONE
# (0→0 mise à jour, 0→1 soumission, 1→1 mise à jour, 1→2 annulation) — jamais
# 0→2 ni décroissant. Le CLI `validate` fait respecter cet invariant.
DOCSTATUS_DRAFT = "0"
DOCSTATUS_SUBMITTED = "1"
DOCSTATUS_CANCELLED = "2"
VALID_DOCSTATUS: frozenset[str] = frozenset(
    {DOCSTATUS_DRAFT, DOCSTATUS_SUBMITTED, DOCSTATUS_CANCELLED}
)

# Styles d'affichage natifs du DocType `Workflow State` (badge de couleur desk).
# Une valeur hors de cet ensemble = invention → refusée.
VALID_STYLES: frozenset[str] = frozenset(
    {"", "Primary", "Info", "Success", "Warning", "Danger", "Inverse"}
)


def workflow_state_master(state: str, style: str) -> dict[str, Any]:
    """DocType maître `Workflow State` (nom + style de badge)."""
    if style not in VALID_STYLES:
        raise ValueError(f"Style non natif Frappe pour {state!r} : {style!r}")
    return {"doctype": "Workflow State", "name": state, "workflow_state_name": state, "style": style}


def workflow_action_master(action: str) -> dict[str, Any]:
    """DocType maître `Workflow Action Master` (nom d'action)."""
    return {"doctype": "Workflow Action Master", "name": action, "workflow_action_name": action}


def document_state_row(
    state: str,
    doc_status: str,
    allow_edit: str,
    *,
    update_field: str,
    update_value: str,
    message: str,
) -> dict[str, Any]:
    """Ligne de la table enfant `states` d'un Workflow."""
    if doc_status not in VALID_DOCSTATUS:
        raise ValueError(f"doc_status non natif pour {state!r} : {doc_status!r}")
    return {
        "state": state,
        "doc_status": doc_status,
        "allow_edit": allow_edit,
        "update_field": update_field,
        "update_value": update_value,
        "is_optional_state": 0,
        "message": message,
    }


def transition_row(
    state: str,
    action: str,
    next_state: str,
    allowed: str,
    *,
    allow_self_approval: int,
) -> dict[str, Any]:
    """Ligne de la table enfant `transitions` d'un Workflow."""
    return {
        "state": state,
        "action": action,
        "next_state": next_state,
        "allowed": allowed,
        "allow_self_approval": 1 if allow_self_approval else 0,
        "condition": None,
    }


def workflow_doc(
    *,
    name: str,
    document_type: str,
    workflow_state_field: str,
    is_active: int,
    send_email_alert: int,
    override_status: int,
    states: list[dict],
    transitions: list[dict],
) -> dict[str, Any]:
    """Le document `Workflow` complet (states + transitions en tables enfant)."""
    return {
        "doctype": "Workflow",
        "name": name,
        "workflow_name": name,
        "document_type": document_type,
        "workflow_state_field": workflow_state_field,
        "is_active": 1 if is_active else 0,
        "send_email_alert": 1 if send_email_alert else 0,
        "override_status": 1 if override_status else 0,
        "states": states,
        "transitions": transitions,
    }
