# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""
Refresh accounting data from external system (e.g. Abacus) into local TrusteeData* tables.
Checks lastSyncAt to avoid redundant imports unless forceRefresh is set.
"""

import json
import logging
import time
from typing import Dict, Any

from modules.datamodels.datamodelChat import ActionResult

logger = logging.getLogger(__name__)

_SYNC_THRESHOLD_SECONDS = 3600


async def refreshAccountingData(self, parameters: Dict[str, Any]) -> ActionResult:
    """Import/refresh accounting data from the configured external system.

    If data was synced within the last hour and forceRefresh is not set,
    returns cached counts without triggering an external sync.
    """
    featureInstanceId = parameters.get("featureInstanceId") or (
        self.services.featureInstanceId if hasattr(self.services, "featureInstanceId") else None
    )
    forceRefresh = parameters.get("forceRefresh", False)
    if isinstance(forceRefresh, str):
        forceRefresh = forceRefresh.lower() in ("true", "1", "yes")
    dateFrom = parameters.get("dateFrom") or None
    dateTo = parameters.get("dateTo") or None

    if not featureInstanceId:
        return ActionResult.isFailure(error="featureInstanceId is required")

    try:
        from modules.features.trustee.interfaceFeatureTrustee import getInterface as getTrusteeInterface
        from modules.features.trustee.datamodelFeatureTrustee import (
            TrusteeAccountingConfig,
            TrusteeDataAccount,
            TrusteeDataJournalEntry,
            TrusteeDataJournalLine,
            TrusteeDataContact,
            TrusteeDataAccountBalance,
        )

        trusteeInterface = getTrusteeInterface(
            self.services.user,
            mandateId=self.services.mandateId,
            featureInstanceId=featureInstanceId,
        )

        cfgRecords = trusteeInterface.db.getRecordset(
            TrusteeAccountingConfig,
            recordFilter={"featureInstanceId": featureInstanceId, "isActive": True},
        )
        if not cfgRecords:
            return ActionResult.isFailure(error="No active accounting configuration found for this Trustee instance")

        cfgRecord = cfgRecords[0]
        lastSyncAt = cfgRecord.get("lastSyncAt") or 0
        lastSyncStatus = cfgRecord.get("lastSyncStatus") or ""

        isFresh = (
            lastSyncAt
            and (time.time() - lastSyncAt) < _SYNC_THRESHOLD_SECONDS
            and lastSyncStatus in ("success", "partial")
        )

        if isFresh and not forceRefresh:
            counts = _getCachedCounts(trusteeInterface, featureInstanceId)
            counts["synced"] = False
            counts["lastSyncAt"] = lastSyncAt
            counts["lastSyncStatus"] = lastSyncStatus
            counts["message"] = f"Data is fresh (synced {int(time.time() - lastSyncAt)}s ago). Use forceRefresh=true to re-import."
            dataExport = _exportAccountingData(trusteeInterface, featureInstanceId, dateFrom, dateTo)
            return ActionResult.isSuccess(data={
                "summary": counts,
                "accountingData": dataExport,
            })

        from modules.features.trustee.accounting.accountingDataSync import AccountingDataSync

        sync = AccountingDataSync(trusteeInterface)
        summary = await sync.importData(
            featureInstanceId=featureInstanceId,
            mandateId=self.services.mandateId,
            dateFrom=dateFrom,
            dateTo=dateTo,
        )
        summary["synced"] = True
        summary.pop("startedAt", None)
        summary.pop("finishedAt", None)

        try:
            from modules.serviceCenter.services.serviceAgent.coreTools._featureSubAgentTools import clearFeatureQueryCache
            clearFeatureQueryCache(featureInstanceId)
            logger.info("Cleared feature query cache for instance %s after accounting import", featureInstanceId)
        except Exception as cacheErr:
            logger.warning("Could not clear feature query cache: %s", cacheErr)

        dataExport = _exportAccountingData(trusteeInterface, featureInstanceId, dateFrom, dateTo)
        return ActionResult.isSuccess(data={
            "summary": summary,
            "accountingData": dataExport,
        })
    except Exception as e:
        logger.exception("refreshAccountingData failed")
        return ActionResult.isFailure(error=str(e))


def _exportAccountingData(trusteeInterface, featureInstanceId: str, dateFrom: str = None, dateTo: str = None) -> str:
    """Export accounting data (accounts, balances, journal entries+lines) as compact JSON for downstream AI nodes."""
    from modules.features.trustee.datamodelFeatureTrustee import (
        TrusteeDataAccount,
        TrusteeDataJournalEntry,
        TrusteeDataJournalLine,
        TrusteeDataAccountBalance,
    )
    try:
        baseFilter = {"featureInstanceId": featureInstanceId}

        accounts = trusteeInterface.db.getRecordset(TrusteeDataAccount, recordFilter=baseFilter) or []
        accountMap = {}
        for a in accounts:
            nr = a.get("accountNumber", "")
            accountMap[nr] = {
                "nr": nr,
                "label": a.get("label", ""),
                "type": a.get("accountType", ""),
                "group": a.get("accountGroup", ""),
            }

        balances = trusteeInterface.db.getRecordset(TrusteeDataAccountBalance, recordFilter=baseFilter) or []
        balanceList = []
        for b in balances:
            balanceList.append({
                "account": b.get("accountNumber", ""),
                "year": b.get("periodYear", 0),
                "month": b.get("periodMonth", 0),
                "opening": b.get("openingBalance", 0),
                "debit": b.get("debitTotal", 0),
                "credit": b.get("creditTotal", 0),
                "closing": b.get("closingBalance", 0),
            })

        entries = trusteeInterface.db.getRecordset(TrusteeDataJournalEntry, recordFilter=baseFilter) or []
        entryMap = {}
        for e in entries:
            eid = e.get("id", "")
            bDate = e.get("bookingDate", "")
            if dateFrom and bDate and bDate < dateFrom:
                continue
            if dateTo and bDate and bDate > dateTo:
                continue
            entryMap[eid] = {
                "date": bDate,
                "ref": e.get("reference", ""),
                "desc": e.get("description", ""),
                "amount": e.get("totalAmount", 0),
            }

        lines = trusteeInterface.db.getRecordset(TrusteeDataJournalLine, recordFilter=baseFilter) or []
        lineList = []
        for ln in lines:
            jeId = ln.get("journalEntryId", "")
            if jeId not in entryMap:
                continue
            entry = entryMap[jeId]
            lineList.append({
                "date": entry["date"],
                "ref": entry["ref"],
                "account": ln.get("accountNumber", ""),
                "accountLabel": accountMap.get(ln.get("accountNumber", ""), {}).get("label", ""),
                "debit": ln.get("debitAmount", 0),
                "credit": ln.get("creditAmount", 0),
                "desc": ln.get("description", "") or entry["desc"],
                "taxCode": ln.get("taxCode", ""),
                "costCenter": ln.get("costCenter", ""),
            })

        export = {
            "accounts": list(accountMap.values()),
            "balances": balanceList,
            "journalLines": lineList,
            "meta": {
                "accountCount": len(accountMap),
                "entryCount": len(entryMap),
                "lineCount": len(lineList),
                "balanceCount": len(balanceList),
                "dateFrom": dateFrom,
                "dateTo": dateTo,
            },
        }
        result = json.dumps(export, ensure_ascii=False, default=str)
        logger.info("Exported accounting data: %d accounts, %d entries, %d lines, %d balances (%d bytes)",
                     len(accountMap), len(entryMap), len(lineList), len(balanceList), len(result))
        return result
    except Exception as e:
        logger.warning("Could not export accounting data: %s", e)
        return ""


def _getCachedCounts(trusteeInterface, featureInstanceId: str) -> Dict[str, Any]:
    """Count existing records per TrusteeData* table without triggering an external sync."""
    from modules.features.trustee.datamodelFeatureTrustee import (
        TrusteeDataAccount,
        TrusteeDataJournalEntry,
        TrusteeDataJournalLine,
        TrusteeDataContact,
        TrusteeDataAccountBalance,
    )
    counts = {}
    for label, model in [
        ("accounts", TrusteeDataAccount),
        ("journalEntries", TrusteeDataJournalEntry),
        ("journalLines", TrusteeDataJournalLine),
        ("contacts", TrusteeDataContact),
        ("accountBalances", TrusteeDataAccountBalance),
    ]:
        records = trusteeInterface.db.getRecordset(
            model, recordFilter={"featureInstanceId": featureInstanceId}
        )
        counts[label] = len(records) if records else 0
    return counts
