# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""Trustee models: TrusteeOrganisation, TrusteeRole, TrusteeAccess, TrusteeContract, TrusteeDocument, TrusteePosition."""

from enum import Enum
from typing import Optional
from pydantic import BaseModel, Field

from modules.datamodels.datamodelBase import PowerOnModel
from modules.shared.attributeUtils import registerModelLabels
import uuid


class TrusteeOrganisation(PowerOnModel):
    """Represents trustee organisations (companies) within the Trustee feature."""
    id: str = Field(  # Unique string label (PK), not UUID
        description="Unique organisation identifier (label)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,  # Editable at creation, then readonly
            "frontend_required": True
        }
    )
    label: str = Field(
        description="Company name",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": True
        }
    )
    enabled: bool = Field(
        default=True,
        description="Whether the organisation is enabled",
        json_schema_extra={
            "frontend_type": "checkbox",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    mandateId: Optional[str] = Field(
        default=None,
        description="Mandate ID (system-level organisation)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    featureInstanceId: Optional[str] = Field(
        default=None,
        description="Feature Instance ID for instance-level isolation",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    # System attributes are automatically set by DatabaseConnector:
    # sysCreatedAt, sysModifiedAt, sysCreatedBy, sysModifiedBy (PowerOnModel)


registerModelLabels(
    "TrusteeOrganisation",
    {"en": "Organisation", "fr": "Organisation", "de": "Organisation"},
    {
        "id": {"en": "ID", "fr": "ID", "de": "ID"},
        "label": {"en": "Label", "fr": "Libellé", "de": "Bezeichnung"},
        "enabled": {"en": "Enabled", "fr": "Activé", "de": "Aktiviert"},
        "mandateId": {"en": "Mandate", "fr": "Mandat", "de": "Mandat"},
        "featureInstanceId": {"en": "Feature Instance", "fr": "Instance de fonctionnalité", "de": "Feature-Instanz"},
    },
)


class TrusteeRole(PowerOnModel):
    """Defines roles within the Trustee feature."""
    id: str = Field(  # Unique string label (PK), not UUID
        description="Unique role identifier (label)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": True
        }
    )
    desc: str = Field(
        description="Role description",
        json_schema_extra={
            "frontend_type": "textarea",
            "frontend_readonly": False,
            "frontend_required": True
        }
    )
    mandateId: Optional[str] = Field(
        default=None,
        description="Mandate ID",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    featureInstanceId: Optional[str] = Field(
        default=None,
        description="Feature Instance ID for instance-level isolation",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    # System attributes are automatically set by DatabaseConnector


registerModelLabels(
    "TrusteeRole",
    {"en": "Role", "fr": "Rôle", "de": "Rolle"},
    {
        "id": {"en": "ID", "fr": "ID", "de": "ID"},
        "desc": {"en": "Description", "fr": "Description", "de": "Beschreibung"},
        "mandateId": {"en": "Mandate", "fr": "Mandat", "de": "Mandat"},
        "featureInstanceId": {"en": "Feature Instance", "fr": "Instance de fonctionnalité", "de": "Feature-Instanz"},
    },
)


class TrusteeAccess(PowerOnModel):
    """Defines user access to organisations with specific roles."""
    id: str = Field(
        default_factory=lambda: str(uuid.uuid4()),
        description="Unique access ID",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    organisationId: str = Field(
        description="Reference to TrusteeOrganisation.id",
        json_schema_extra={
            "frontend_type": "select",
            "frontend_readonly": False,
            "frontend_required": True,
            "frontend_options": "/api/trustee/{instanceId}/organisations/options"
        }
    )
    roleId: str = Field(
        description="Reference to TrusteeRole.id",
        json_schema_extra={
            "frontend_type": "select",
            "frontend_readonly": False,
            "frontend_required": True,
            "frontend_options": "/api/trustee/{instanceId}/roles/options"
        }
    )
    userId: str = Field(
        description="User ID assigned to this role",
        json_schema_extra={
            "frontend_type": "select",
            "frontend_readonly": False,
            "frontend_required": True,
            "frontend_options": "/api/users/options"
        }
    )
    contractId: Optional[str] = Field(
        default=None,
        description="Optional reference to TrusteeContract.id. If None, access is for full organisation. If set, access is limited to this specific contract.",
        json_schema_extra={
            "frontend_type": "select",
            "frontend_readonly": False,
            "frontend_required": False,
            "frontend_options": "/api/trustee/{instanceId}/contracts/options",
            "frontend_depends_on": "organisationId"
        }
    )
    mandateId: Optional[str] = Field(
        default=None,
        description="Mandate ID",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    featureInstanceId: Optional[str] = Field(
        default=None,
        description="Feature Instance ID for instance-level isolation",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    # System attributes are automatically set by DatabaseConnector


registerModelLabels(
    "TrusteeAccess",
    {"en": "Access", "fr": "Accès", "de": "Zugriff"},
    {
        "id": {"en": "ID", "fr": "ID", "de": "ID"},
        "organisationId": {"en": "Organisation", "fr": "Organisation", "de": "Organisation"},
        "roleId": {"en": "Role", "fr": "Rôle", "de": "Rolle"},
        "userId": {"en": "User", "fr": "Utilisateur", "de": "Benutzer"},
        "contractId": {"en": "Contract (optional)", "fr": "Contrat (optionnel)", "de": "Vertrag (optional)"},
        "mandateId": {"en": "Mandate", "fr": "Mandat", "de": "Mandat"},
        "featureInstanceId": {"en": "Feature Instance", "fr": "Instance de fonctionnalité", "de": "Feature-Instanz"},
    },
)


class TrusteeContract(PowerOnModel):
    """Defines customer contracts within organisations."""
    id: str = Field(
        default_factory=lambda: str(uuid.uuid4()),
        description="Unique contract ID",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    organisationId: str = Field(
        description="Reference to TrusteeOrganisation.id (immutable after creation)",
        json_schema_extra={
            "frontend_type": "select",
            "frontend_readonly": False,  # Editable at creation, then readonly
            "frontend_required": True,
            "frontend_options": "/api/trustee/{instanceId}/organisations/options"
        }
    )
    label: str = Field(
        description="Label for the customer contract (e.g., 'Muster AG 2026')",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": True
        }
    )
    enabled: bool = Field(
        default=True,
        description="Whether the contract is enabled",
        json_schema_extra={
            "frontend_type": "checkbox",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    mandateId: Optional[str] = Field(
        default=None,
        description="Mandate ID",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    featureInstanceId: Optional[str] = Field(
        default=None,
        description="Feature Instance ID for instance-level isolation",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    # System attributes are automatically set by DatabaseConnector


registerModelLabels(
    "TrusteeContract",
    {"en": "Contract", "fr": "Contrat", "de": "Vertrag"},
    {
        "id": {"en": "ID", "fr": "ID", "de": "ID"},
        "organisationId": {"en": "Organisation", "fr": "Organisation", "de": "Organisation"},
        "label": {"en": "Label", "fr": "Libellé", "de": "Bezeichnung"},
        "enabled": {"en": "Enabled", "fr": "Activé", "de": "Aktiviert"},
        "mandateId": {"en": "Mandate", "fr": "Mandat", "de": "Mandat"},
        "featureInstanceId": {"en": "Feature Instance", "fr": "Instance de fonctionnalité", "de": "Feature-Instanz"},
    },
)


class TrusteeDocumentTypeEnum(str, Enum):
    """Document type for trustee documents (expense extraction, ingest, sync)."""
    INVOICE = "invoice"
    EXPENSE_RECEIPT = "expense_receipt"
    BANK_DOCUMENT = "bank_document"
    CONTRACT = "contract"
    UNKNOWN = "unknown"
    AUTO = "auto"


class TrusteeDocument(PowerOnModel):
    """Contains document references for bookings.
    
    Documents reference files in the central Files table via fileId.
    This allows file content to be stored once and referenced by multiple features.
    
    Note: organisationId and contractId removed as per architecture decision:
    - The feature instance IS the organisation
    - Contracts are eliminated from the model
    """
    id: str = Field(
        default_factory=lambda: str(uuid.uuid4()),
        description="Unique document ID",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    fileId: Optional[str] = Field(
        default=None,
        description="Reference to central Files table (Files.id)",
        json_schema_extra={
            "frontend_type": "file_reference",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    documentName: str = Field(
        description="File name (e.g., 'Beleg.pdf')",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": True
        }
    )
    documentMimeType: str = Field(
        default="application/octet-stream",
        description="MIME type of the document",
        json_schema_extra={
            "frontend_type": "select",
            "frontend_readonly": False,
            "frontend_required": True,
            "frontend_options": "/api/trustee/mime-types/options"
        }
    )
    sourceType: Optional[str] = Field(
        default=None,
        description="Source type (e.g., 'sharepoint', 'upload', 'email')",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    sourceLocation: Optional[str] = Field(
        default=None,
        description="Original source location (e.g., SharePoint path)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    mandateId: Optional[str] = Field(
        default=None,
        description="Mandate ID (auto-set from context)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False,
            "frontend_hidden": True
        }
    )
    featureInstanceId: Optional[str] = Field(
        default=None,
        description="Feature Instance ID for instance-level isolation (auto-set from context)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False,
            "frontend_hidden": True
        }
    )
    documentType: Optional[str] = Field(
        default=None,
        description="Document type (e.g. invoice, expense_receipt, bank_document, contract); use TrusteeDocumentTypeEnum values",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    externalBelegId: Optional[str] = Field(
        default=None,
        description="External Beleg-ID in accounting system (e.g. RMA); set on first successful upload, reused on re-sync",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False,
            "frontend_hidden": True
        }
    )
    # System attributes are automatically set by DatabaseConnector


registerModelLabels(
    "TrusteeDocument",
    {"en": "Document", "fr": "Document", "de": "Dokument"},
    {
        "id": {"en": "ID", "fr": "ID", "de": "ID"},
        "fileId": {"en": "File Reference", "fr": "Référence du fichier", "de": "Datei-Referenz"},
        "documentName": {"en": "Document Name", "fr": "Nom du document", "de": "Dokumentname"},
        "documentMimeType": {"en": "MIME Type", "fr": "Type MIME", "de": "MIME-Typ"},
        "sourceType": {"en": "Source Type", "fr": "Type de source", "de": "Quelltyp"},
        "sourceLocation": {"en": "Source Location", "fr": "Emplacement source", "de": "Quellort"},
        "mandateId": {"en": "Mandate", "fr": "Mandat", "de": "Mandat"},
        "featureInstanceId": {"en": "Feature Instance", "fr": "Instance de fonctionnalité", "de": "Feature-Instanz"},
        "documentType": {"en": "Document Type", "fr": "Type de document", "de": "Dokumenttyp"},
        "externalBelegId": {"en": "Beleg ID (Accounting)", "fr": "ID Beleg (Comptabilité)", "de": "Beleg-ID (Buchhaltung)"},
    },
)


class TrusteePosition(PowerOnModel):
    """Contains booking positions (expense entries).
    
    A position can have up to two document references: documentId (Beleg) and bankDocumentId (Bank-Referenz).
    One document (e.g. bank statement) can generate many positions.
    """
    id: str = Field(
        default_factory=lambda: str(uuid.uuid4()),
        description="Unique position ID",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False
        }
    )
    documentId: Optional[str] = Field(
        default=None,
        description="Reference to TrusteeDocument.id (Beleg / primary document)",
        json_schema_extra={
            "frontend_type": "select",
            "frontend_readonly": False,
            "frontend_required": False,
            "frontend_options": "/api/trustee/{instanceId}/documents/options"
        }
    )
    bankDocumentId: Optional[str] = Field(
        default=None,
        description="Reference to TrusteeDocument.id (Bank-Referenz / second document)",
        json_schema_extra={
            "frontend_type": "select",
            "frontend_readonly": False,
            "frontend_required": False,
            "frontend_options": "/api/trustee/{instanceId}/documents/options"
        }
    )
    valuta: Optional[str] = Field(
        default=None,
        description="Value date (ISO format: YYYY-MM-DD)",
        json_schema_extra={
            "frontend_type": "date",
            "frontend_readonly": False,
            "frontend_required": True
        }
    )
    transactionDateTime: Optional[float] = Field(
        default=None,
        description="Transaction timestamp (UTC timestamp in seconds)",
        json_schema_extra={
            "frontend_type": "timestamp",
            "frontend_readonly": False,
            "frontend_required": True
        }
    )
    company: str = Field(
        default="",
        description="Company name",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    desc: str = Field(
        default="",
        description="Description",
        json_schema_extra={
            "frontend_type": "textarea",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    tags: str = Field(
        default="",
        description="Tags (comma-separated)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    bookingCurrency: str = Field(
        default="CHF",
        description="Booking currency code",
        json_schema_extra={
            "frontend_type": "select",
            "frontend_readonly": False,
            "frontend_required": True,
            "frontend_options": [
                {"value": "CHF", "label": {"en": "CHF", "fr": "CHF", "de": "CHF"}},
                {"value": "EUR", "label": {"en": "EUR", "fr": "EUR", "de": "EUR"}},
                {"value": "USD", "label": {"en": "USD", "fr": "USD", "de": "USD"}},
                {"value": "GBP", "label": {"en": "GBP", "fr": "GBP", "de": "GBP"}},
            ]
        }
    )
    bookingAmount: float = Field(
        default=0.0,
        description="Booking amount",
        json_schema_extra={
            "frontend_type": "number",
            "frontend_readonly": False,
            "frontend_required": True
        }
    )
    originalCurrency: str = Field(
        default="CHF",
        description="Original currency code",
        json_schema_extra={
            "frontend_type": "select",
            "frontend_readonly": False,
            "frontend_required": True,
            "frontend_options": [
                {"value": "CHF", "label": {"en": "CHF", "fr": "CHF", "de": "CHF"}},
                {"value": "EUR", "label": {"en": "EUR", "fr": "EUR", "de": "EUR"}},
                {"value": "USD", "label": {"en": "USD", "fr": "USD", "de": "USD"}},
                {"value": "GBP", "label": {"en": "GBP", "fr": "GBP", "de": "GBP"}},
            ]
        }
    )
    originalAmount: float = Field(
        default=0.0,
        description="Original amount (manual input, no automatic currency conversion)",
        json_schema_extra={
            "frontend_type": "number",
            "frontend_readonly": False,
            "frontend_required": True
        }
    )
    vatPercentage: float = Field(
        default=0.0,
        description="VAT percentage",
        json_schema_extra={
            "frontend_type": "number",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    vatAmount: float = Field(
        default=0.0,
        description="VAT amount (calculated: bookingAmount * vatPercentage / 100, can be manually overridden)",
        json_schema_extra={
            "frontend_type": "number",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    debitAccountNumber: Optional[str] = Field(
        default=None,
        description="Debit account number (e.g. '4200' for expenses)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    creditAccountNumber: Optional[str] = Field(
        default=None,
        description="Credit account number (e.g. '1020' for bank)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    taxCode: Optional[str] = Field(
        default=None,
        description="Tax code for the accounting system",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    costCenter: Optional[str] = Field(
        default=None,
        description="Cost center identifier",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    bookingReference: Optional[str] = Field(
        default=None,
        description="Booking reference (e.g. voucher number)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    documentType: Optional[str] = Field(
        default=None,
        description="Document type that generated this position (invoice, expense_receipt, bank_document, contract, unknown)",
        json_schema_extra={
            "frontend_type": "select",
            "frontend_readonly": True,
            "frontend_required": False,
            "frontend_options": [
                {"value": "invoice", "label": {"en": "Invoice", "fr": "Facture", "de": "Rechnung"}},
                {"value": "expense_receipt", "label": {"en": "Expense Receipt", "fr": "Reçu", "de": "Beleg"}},
                {"value": "bank_document", "label": {"en": "Bank Statement", "fr": "Relevé bancaire", "de": "Bankauszug"}},
                {"value": "contract", "label": {"en": "Contract", "fr": "Contrat", "de": "Vertrag"}},
                {"value": "unknown", "label": {"en": "Other", "fr": "Autre", "de": "Sonstige"}},
            ]
        }
    )
    payeeIban: Optional[str] = Field(
        default=None,
        description="IBAN of the payment recipient (from invoice / QR code)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    payeeName: Optional[str] = Field(
        default=None,
        description="Bank or account holder name of the payment recipient",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    payeeBic: Optional[str] = Field(
        default=None,
        description="BIC / SWIFT code of the recipient bank",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    paymentReference: Optional[str] = Field(
        default=None,
        description="Structured payment reference (QR-Referenz, ESR, SCOR, Mitteilung)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    dueDate: Optional[str] = Field(
        default=None,
        description="Payment due date (ISO format: YYYY-MM-DD)",
        json_schema_extra={
            "frontend_type": "date",
            "frontend_readonly": False,
            "frontend_required": False
        }
    )
    mandateId: Optional[str] = Field(
        default=None,
        description="Mandate ID (auto-set from context)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False,
            "frontend_hidden": True
        }
    )
    featureInstanceId: Optional[str] = Field(
        default=None,
        description="Feature Instance ID for instance-level isolation (auto-set from context)",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False,
            "frontend_hidden": True
        }
    )
    accountingSyncId: Optional[str] = Field(
        default=None,
        description="External ID (UUID) of the synced record in the accounting system; set by sync, used for duplicate check",
        json_schema_extra={
            "frontend_type": "text",
            "frontend_readonly": True,
            "frontend_required": False,
            "frontend_hidden": True
        }
    )

registerModelLabels(
    "TrusteePosition",
    {"en": "Position", "fr": "Position", "de": "Position"},
    {
        "id": {"en": "ID", "fr": "ID", "de": "ID"},
        "documentId": {"en": "Document", "fr": "Document", "de": "Dokument"},
        "bankDocumentId": {"en": "Bank Reference", "fr": "Référence bancaire", "de": "Bank-Referenz"},
        "valuta": {"en": "Value Date", "fr": "Date de valeur", "de": "Valutadatum"},
        "transactionDateTime": {"en": "Transaction Date/Time", "fr": "Date/Heure de transaction", "de": "Transaktionszeitpunkt"},
        "company": {"en": "Company", "fr": "Entreprise", "de": "Firma"},
        "desc": {"en": "Description", "fr": "Description", "de": "Beschreibung"},
        "tags": {"en": "Tags", "fr": "Tags", "de": "Tags"},
        "bookingCurrency": {"en": "Booking Currency", "fr": "Devise de comptabilisation", "de": "Buchungswährung"},
        "bookingAmount": {"en": "Booking Amount", "fr": "Montant de comptabilisation", "de": "Buchungsbetrag"},
        "originalCurrency": {"en": "Original Currency", "fr": "Devise d'origine", "de": "Originalwährung"},
        "originalAmount": {"en": "Original Amount", "fr": "Montant d'origine", "de": "Originalbetrag"},
        "vatPercentage": {"en": "VAT Percentage", "fr": "Pourcentage TVA", "de": "MwSt-Prozentsatz"},
        "vatAmount": {"en": "VAT Amount", "fr": "Montant TVA", "de": "MwSt-Betrag"},
        "debitAccountNumber": {"en": "Debit Account", "fr": "Compte débit", "de": "Soll-Konto"},
        "creditAccountNumber": {"en": "Credit Account", "fr": "Compte crédit", "de": "Haben-Konto"},
        "taxCode": {"en": "Tax Code", "fr": "Code TVA", "de": "Steuercode"},
        "costCenter": {"en": "Cost Center", "fr": "Centre de coûts", "de": "Kostenstelle"},
        "bookingReference": {"en": "Booking Reference", "fr": "Référence de réservation", "de": "Buchungsreferenz"},
        "documentType": {"en": "Document Type", "fr": "Type de document", "de": "Dokumenttyp"},
        "payeeIban": {"en": "Payee IBAN", "fr": "IBAN bénéficiaire", "de": "Empfänger-IBAN"},
        "payeeName": {"en": "Payee Name", "fr": "Nom du bénéficiaire", "de": "Empfänger-Name"},
        "payeeBic": {"en": "Payee BIC/SWIFT", "fr": "BIC/SWIFT bénéficiaire", "de": "Empfänger-BIC"},
        "paymentReference": {"en": "Payment Reference", "fr": "Référence de paiement", "de": "Zahlungsreferenz"},
        "dueDate": {"en": "Due Date", "fr": "Date d'échéance", "de": "Fälligkeitsdatum"},
        "mandateId": {"en": "Mandate", "fr": "Mandat", "de": "Mandat"},
        "featureInstanceId": {"en": "Feature Instance", "fr": "Instance de fonctionnalité", "de": "Feature-Instanz"},
        "accountingSyncId": {"en": "Accounting Sync ID", "fr": "ID sync comptabilité", "de": "Buha-Sync-ID"},
    },
)


# ── TrusteeData* tables (synced from external accounting apps for analysis) ──


class TrusteeDataAccount(PowerOnModel):
    """Chart of accounts synced from external accounting system."""
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    accountNumber: str = Field(description="Account number (e.g. '1020')")
    label: str = Field(default="", description="Account name")
    accountType: Optional[str] = Field(default=None, description="asset / liability / equity / revenue / expense")
    accountGroup: Optional[str] = Field(default=None, description="Account group/category")
    currency: str = Field(default="CHF", description="Account currency")
    isActive: bool = Field(default=True)
    mandateId: Optional[str] = Field(default=None)
    featureInstanceId: Optional[str] = Field(default=None)


registerModelLabels(
    "TrusteeDataAccount",
    {"en": "Account (Synced)", "de": "Konto (Sync)", "fr": "Compte (Sync)"},
    {
        "id": {"en": "ID", "de": "ID", "fr": "ID"},
        "accountNumber": {"en": "Account Number", "de": "Kontonummer", "fr": "Numéro de compte"},
        "label": {"en": "Name", "de": "Bezeichnung", "fr": "Libellé"},
        "accountType": {"en": "Type", "de": "Typ", "fr": "Type"},
        "accountGroup": {"en": "Group", "de": "Gruppe", "fr": "Groupe"},
        "currency": {"en": "Currency", "de": "Währung", "fr": "Devise"},
        "isActive": {"en": "Active", "de": "Aktiv", "fr": "Actif"},
        "mandateId": {"en": "Mandate", "de": "Mandat", "fr": "Mandat"},
        "featureInstanceId": {"en": "Feature Instance", "de": "Feature-Instanz", "fr": "Instance"},
    },
)


class TrusteeDataJournalEntry(PowerOnModel):
    """Journal entry header synced from external accounting system."""
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    externalId: Optional[str] = Field(default=None, description="ID in the source system")
    bookingDate: Optional[str] = Field(default=None, description="Booking date (YYYY-MM-DD)")
    reference: Optional[str] = Field(default=None, description="Booking reference / voucher number")
    description: str = Field(default="", description="Booking text")
    currency: str = Field(default="CHF")
    totalAmount: float = Field(default=0.0, description="Total amount of entry")
    mandateId: Optional[str] = Field(default=None)
    featureInstanceId: Optional[str] = Field(default=None)


registerModelLabels(
    "TrusteeDataJournalEntry",
    {"en": "Journal Entry (Synced)", "de": "Buchung (Sync)", "fr": "Écriture (Sync)"},
    {
        "id": {"en": "ID", "de": "ID", "fr": "ID"},
        "externalId": {"en": "External ID", "de": "Externe ID", "fr": "ID externe"},
        "bookingDate": {"en": "Date", "de": "Datum", "fr": "Date"},
        "reference": {"en": "Reference", "de": "Referenz", "fr": "Référence"},
        "description": {"en": "Description", "de": "Beschreibung", "fr": "Description"},
        "currency": {"en": "Currency", "de": "Währung", "fr": "Devise"},
        "totalAmount": {"en": "Amount", "de": "Betrag", "fr": "Montant"},
        "mandateId": {"en": "Mandate", "de": "Mandat", "fr": "Mandat"},
        "featureInstanceId": {"en": "Feature Instance", "de": "Feature-Instanz", "fr": "Instance"},
    },
)


class TrusteeDataJournalLine(PowerOnModel):
    """Journal entry line (debit/credit) synced from external accounting system."""
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    journalEntryId: str = Field(description="FK → TrusteeDataJournalEntry.id")
    accountNumber: str = Field(description="Account number")
    debitAmount: float = Field(default=0.0)
    creditAmount: float = Field(default=0.0)
    currency: str = Field(default="CHF")
    taxCode: Optional[str] = Field(default=None)
    costCenter: Optional[str] = Field(default=None)
    description: str = Field(default="")
    mandateId: Optional[str] = Field(default=None)
    featureInstanceId: Optional[str] = Field(default=None)


registerModelLabels(
    "TrusteeDataJournalLine",
    {"en": "Journal Line (Synced)", "de": "Buchungszeile (Sync)", "fr": "Ligne écriture (Sync)"},
    {
        "id": {"en": "ID", "de": "ID", "fr": "ID"},
        "journalEntryId": {"en": "Journal Entry", "de": "Buchung", "fr": "Écriture"},
        "accountNumber": {"en": "Account", "de": "Konto", "fr": "Compte"},
        "debitAmount": {"en": "Debit", "de": "Soll", "fr": "Débit"},
        "creditAmount": {"en": "Credit", "de": "Haben", "fr": "Crédit"},
        "currency": {"en": "Currency", "de": "Währung", "fr": "Devise"},
        "taxCode": {"en": "Tax Code", "de": "Steuercode", "fr": "Code TVA"},
        "costCenter": {"en": "Cost Center", "de": "Kostenstelle", "fr": "Centre de coûts"},
        "description": {"en": "Description", "de": "Beschreibung", "fr": "Description"},
        "mandateId": {"en": "Mandate", "de": "Mandat", "fr": "Mandat"},
        "featureInstanceId": {"en": "Feature Instance", "de": "Feature-Instanz", "fr": "Instance"},
    },
)


class TrusteeDataContact(PowerOnModel):
    """Customer or vendor synced from external accounting system."""
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    externalId: Optional[str] = Field(default=None, description="ID in the source system")
    contactType: str = Field(default="customer", description="customer / vendor / both")
    contactNumber: Optional[str] = Field(default=None, description="Customer/vendor number")
    name: str = Field(default="", description="Name / company")
    address: Optional[str] = Field(default=None)
    zip: Optional[str] = Field(default=None)
    city: Optional[str] = Field(default=None)
    country: Optional[str] = Field(default=None)
    email: Optional[str] = Field(default=None)
    phone: Optional[str] = Field(default=None)
    vatNumber: Optional[str] = Field(default=None)
    mandateId: Optional[str] = Field(default=None)
    featureInstanceId: Optional[str] = Field(default=None)


registerModelLabels(
    "TrusteeDataContact",
    {"en": "Contact (Synced)", "de": "Kontakt (Sync)", "fr": "Contact (Sync)"},
    {
        "id": {"en": "ID", "de": "ID", "fr": "ID"},
        "externalId": {"en": "External ID", "de": "Externe ID", "fr": "ID externe"},
        "contactType": {"en": "Type", "de": "Typ", "fr": "Type"},
        "contactNumber": {"en": "Number", "de": "Nummer", "fr": "Numéro"},
        "name": {"en": "Name", "de": "Name", "fr": "Nom"},
        "address": {"en": "Address", "de": "Adresse", "fr": "Adresse"},
        "zip": {"en": "ZIP", "de": "PLZ", "fr": "NPA"},
        "city": {"en": "City", "de": "Ort", "fr": "Ville"},
        "country": {"en": "Country", "de": "Land", "fr": "Pays"},
        "email": {"en": "Email", "de": "E-Mail", "fr": "E-mail"},
        "phone": {"en": "Phone", "de": "Telefon", "fr": "Téléphone"},
        "vatNumber": {"en": "VAT Number", "de": "MWST-Nr.", "fr": "N° TVA"},
        "mandateId": {"en": "Mandate", "de": "Mandat", "fr": "Mandat"},
        "featureInstanceId": {"en": "Feature Instance", "de": "Feature-Instanz", "fr": "Instance"},
    },
)


class TrusteeDataAccountBalance(PowerOnModel):
    """Account balance per period, derived from journal lines or directly from accounting system."""
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    accountNumber: str = Field(description="Account number")
    periodYear: int = Field(description="Fiscal year")
    periodMonth: int = Field(default=0, description="Month (1-12); 0 = annual total")
    openingBalance: float = Field(default=0.0)
    debitTotal: float = Field(default=0.0)
    creditTotal: float = Field(default=0.0)
    closingBalance: float = Field(default=0.0)
    currency: str = Field(default="CHF")
    mandateId: Optional[str] = Field(default=None)
    featureInstanceId: Optional[str] = Field(default=None)


registerModelLabels(
    "TrusteeDataAccountBalance",
    {"en": "Account Balance (Synced)", "de": "Kontosaldo (Sync)", "fr": "Solde compte (Sync)"},
    {
        "id": {"en": "ID", "de": "ID", "fr": "ID"},
        "accountNumber": {"en": "Account", "de": "Konto", "fr": "Compte"},
        "periodYear": {"en": "Year", "de": "Jahr", "fr": "Année"},
        "periodMonth": {"en": "Month", "de": "Monat", "fr": "Mois"},
        "openingBalance": {"en": "Opening Balance", "de": "Eröffnungssaldo", "fr": "Solde d'ouverture"},
        "debitTotal": {"en": "Debit Total", "de": "Soll-Umsatz", "fr": "Total débit"},
        "creditTotal": {"en": "Credit Total", "de": "Haben-Umsatz", "fr": "Total crédit"},
        "closingBalance": {"en": "Closing Balance", "de": "Schlusssaldo", "fr": "Solde de clôture"},
        "currency": {"en": "Currency", "de": "Währung", "fr": "Devise"},
        "mandateId": {"en": "Mandate", "de": "Mandat", "fr": "Mandat"},
        "featureInstanceId": {"en": "Feature Instance", "de": "Feature-Instanz", "fr": "Instance"},
    },
)


class TrusteeAccountingConfig(PowerOnModel):
    """Per-instance accounting system configuration with encrypted credentials.

    Each feature instance can connect to exactly one accounting system.
    Credentials are stored encrypted (decrypted at runtime by the AccountingBridge).
    """
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    featureInstanceId: str = Field(description="FK -> FeatureInstance.id (1:1)")
    connectorType: str = Field(description="Connector type key, e.g. 'rma', 'bexio', 'abacus'")
    displayLabel: str = Field(default="", description="User-visible label for this integration")
    encryptedConfig: str = Field(default="", description="Encrypted JSON blob with connector credentials")
    isActive: bool = Field(default=True)
    lastSyncAt: Optional[float] = Field(default=None, description="Timestamp of last sync attempt")
    lastSyncStatus: Optional[str] = Field(default=None, description="Last sync result: success, error, partial")
    lastSyncErrorMessage: Optional[str] = Field(default=None, description="Error message when lastSyncStatus is error")
    cachedChartOfAccounts: Optional[str] = Field(default=None, description="JSON-serialised chart of accounts cache (list of {accountNumber, label, accountType})")
    chartCachedAt: Optional[float] = Field(default=None, description="Timestamp when cachedChartOfAccounts was last refreshed")
    mandateId: Optional[str] = Field(default=None)


registerModelLabels(
    "TrusteeAccountingConfig",
    {"en": "Accounting Configuration", "de": "Buchhaltungs-Konfiguration", "fr": "Configuration comptable"},
    {
        "id": {"en": "ID", "fr": "ID", "de": "ID"},
        "featureInstanceId": {"en": "Feature Instance", "fr": "Instance", "de": "Feature-Instanz"},
        "connectorType": {"en": "System", "fr": "Système", "de": "System"},
        "displayLabel": {"en": "Label", "fr": "Libellé", "de": "Bezeichnung"},
        "isActive": {"en": "Active", "fr": "Actif", "de": "Aktiv"},
        "lastSyncAt": {"en": "Last Sync", "fr": "Dernière sync.", "de": "Letzte Synchronisation"},
        "lastSyncStatus": {"en": "Status", "fr": "Statut", "de": "Status"},
        "lastSyncErrorMessage": {"en": "Error", "fr": "Erreur", "de": "Fehlermeldung"},
        "cachedChartOfAccounts": {"en": "Cached Chart", "de": "Cached Kontoplan", "fr": "Plan comptable en cache"},
        "chartCachedAt": {"en": "Chart Cached At", "de": "Kontoplan-Cache-Zeitpunkt", "fr": "Horodatage cache plan comptable"},
        "mandateId": {"en": "Mandate", "fr": "Mandat", "de": "Mandat"},
    },
)


class TrusteeAccountingSync(PowerOnModel):
    """Tracks which position was synced to which external system and when.

    Used for duplicate prevention, audit trail, and retry logic.
    """
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    positionId: str = Field(description="FK -> TrusteePosition.id")
    featureInstanceId: str = Field(description="FK -> FeatureInstance.id")
    connectorType: str = Field(description="Connector type at time of sync")
    externalId: Optional[str] = Field(default=None, description="ID assigned by the external system")
    externalReference: Optional[str] = Field(default=None, description="Reference in the external system")
    syncStatus: str = Field(default="pending", description="pending | synced | error | cancelled")
    syncDirection: str = Field(default="push", description="push (local->ext) or pull (ext->local)")
    syncedAt: Optional[float] = Field(default=None, description="Timestamp of successful sync")
    errorMessage: Optional[str] = Field(default=None)
    bookingPayload: Optional[dict] = Field(default=None, description="Payload sent to the external system (audit)")
    mandateId: Optional[str] = Field(default=None)


registerModelLabels(
    "TrusteeAccountingSync",
    {"en": "Accounting Sync", "de": "Buchhaltungs-Synchronisation", "fr": "Synchronisation comptable"},
    {
        "id": {"en": "ID", "fr": "ID", "de": "ID"},
        "positionId": {"en": "Position", "fr": "Position", "de": "Position"},
        "connectorType": {"en": "System", "fr": "Système", "de": "System"},
        "externalId": {"en": "External ID", "fr": "ID Externe", "de": "Externe ID"},
        "syncStatus": {"en": "Status", "fr": "Statut", "de": "Status"},
        "syncDirection": {"en": "Direction", "fr": "Direction", "de": "Richtung"},
        "syncedAt": {"en": "Synced At", "fr": "Synchronisé à", "de": "Synchronisiert am"},
        "errorMessage": {"en": "Error", "fr": "Erreur", "de": "Fehler"},
        "mandateId": {"en": "Mandate", "fr": "Mandat", "de": "Mandat"},
    },
)
