"""
Service pentru indicatori financiari - agregate din VBAL pentru calculul
ratelor de lichiditate, eficiență, risc și Altman Z-Score

Acest serviciu agregă soldurile din balanța de verificare (VBAL) pe clase
de conturi conform Planului de Conturi General (PCG) românesc.
"""
import logging
from decimal import Decimal
from typing import Optional, Dict, List, Any

from fastapi import Request
from shared.database.oracle_pool import oracle_pool
from ..cache.decorators import cached
from ..models.dashboard import DashboardSummary
from ..models.financial_indicators import (
    BalanceSheetAggregates,
    IndicatorResult,
    LiquidityIndicators,
    EfficiencyIndicators,
    RiskIndicators,
    CashFlowIndicators,
    DynamicsIndicators,
    AltmanZScore,
    ProfitabilityIndicators,
    SolvabilityIndicators,
    FinancialIndicatorsResponse
)

logger = logging.getLogger(__name__)


# Prefixele conturilor conform PCG (Planul de Conturi General) românesc
# Folosite pentru agregarea soldurilor din VBAL
ACCOUNT_GROUPS = {
    # ACTIVE IMOBILIZATE (Clasa 2)
    # 20 - Imobilizări necorporale
    # 21 - Imobilizări corporale
    # 23 - Imobilizări în curs
    # 26 - Imobilizări financiare
    # 28 - Amortizări (se scad - sold creditor)
    # 29 - Ajustări pentru depreciere (se scad - sold creditor)
    "active_imobilizate": {
        "debit": ["20", "21", "23", "26"],  # Active brute (sold debitor)
        "credit": ["28", "29"]  # Amortizări și ajustări (sold creditor - se scad)
    },

    # STOCURI (Clasa 3)
    # 30 - Materii prime
    # 31 - Materiale consumabile
    # 32 - Obiecte de inventar
    # 33 - Producție în curs
    # 34 - Produse finite
    # 35 - Stocuri aflate la terți
    # 36 - Animale
    # 37 - Mărfuri
    # 38 - Ambalaje
    # 39 - Ajustări pentru depreciere (se scad - sold creditor)
    "stocuri": {
        "debit": ["30", "31", "32", "33", "34", "35", "36", "37", "38"],
        "credit": ["39"]  # Ajustări depreciere stocuri
    },

    # CREANȚE (din Clasa 4)
    # 4111 - Clienți
    # 413 - Efecte de primit
    # 418 - Clienți - facturi de întocmit
    # 425 - Avansuri acordate personalului
    # 428 - Alte datorii și creanțe în legătură cu personalul (dacă debitoare)
    # 431 - Asigurări sociale (dacă debitoare)
    # 437 - Ajutor de șomaj (dacă debitoare)
    # 4411 - Impozit pe profit (dacă debitor)
    # 4424 - TVA de recuperat
    # 444 - Impozit pe venituri de natură salarială (dacă debitor)
    # 445 - Subvenții (dacă debitoare)
    # 446 - Alte impozite și taxe (dacă debitoare)
    # 447 - Fonduri speciale (dacă debitoare)
    # 451 - Decontări între entitățile afiliate (dacă debitoare)
    # 453 - Decontări privind interesele de participare (dacă debitoare)
    # 456 - Decontări cu acționarii (dacă debitoare)
    # 461 - Debitori diverși
    # 473 - Decontări din operații în curs (dacă debitoare)
    "creante": {
        "debit": ["4111", "413", "418", "425", "4424", "461"],
        "credit": ["491", "496"]  # Ajustări pentru deprecierea creanțelor
    },

    # DISPONIBILITĂȚI (din Clasa 5)
    # 5121 - Conturi la bănci în lei
    # 5124 - Conturi la bănci în valută
    # 5311 - Casa în lei
    # 5314 - Casa în valută
    # 532 - Alte valori
    # 541 - Acreditive
    # 542 - Avansuri de trezorerie
    "disponibilitati": {
        "debit": ["5121", "5124", "5311", "5314", "532", "541", "542"],
        "credit": []
    },

    # CAPITAL PROPRIU (din Clasa 1)
    # 101 - Capital social
    # 104 - Prime de capital
    # 105 - Rezerve din reevaluare
    # 106 - Rezerve
    # 107 - Rezultatul reportat (poate fi debitor sau creditor)
    # 108 - Interese minoritare
    # 117 - Rezultatul reportat (cont distinct în unele planuri)
    # 121 - Profit sau pierdere (rezultatul exercițiului)
    "capital_propriu": {
        "debit": [],  # Capitalurile sunt în general creditoare
        "credit": ["101", "104", "105", "106"]
    },

    # CAPITAL SOCIAL STRICT (doar contul 101)
    # Folosit pentru calculul Rata ANC / Capital Social conform definiției legale stricte
    # 101 - Capital social subscris și vărsat
    "capital_social_strict": {
        "debit": [],
        "credit": ["101"]  # Doar Capital Social subscris și vărsat
    },

    # REZULTAT (Profit/Pierdere)
    # 107 - Rezultatul reportat
    # 117 - Rezultatul reportat (în unele versiuni PCG)
    # 121 - Profit sau pierdere
    # 129 - Repartizarea profitului (se scade din profit)
    "rezultat": {
        "debit": ["107", "117", "129"],  # Pierdere sau repartizare
        "credit": ["107", "117", "121"]  # Profit
    },

    # DATORII PE TERMEN LUNG (peste 1 an)
    # 161 - Împrumuturi din emisiuni de obligațiuni
    # 162 - Credite bancare pe termen lung
    # 166 - Datorii care privesc imobilizările financiare
    # 167 - Alte împrumuturi și datorii asimilate
    # 168 - Dobânzi aferente împrumuturilor și datoriilor asimilate
    # 169 - Prime privind rambursarea obligațiunilor
    "datorii_termen_lung": {
        "debit": [],
        "credit": ["161", "162", "166", "167", "168", "169"]
    },

    # DATORII CURENTE (sub 1 an)
    # 401 - Furnizori
    # 403 - Efecte de plătit
    # 404 - Furnizori de imobilizări
    # 408 - Furnizori - facturi nesosite
    # 419 - Clienți - creditori
    # 421 - Personal - salarii datorate
    # 423 - Personal - ajutoare materiale datorate
    # 424 - Prime reprezentând participarea personalului la profit
    # 426 - Drepturi de personal neridicate
    # 427 - Rețineri din salarii datorate terților
    # 431 - Asigurări sociale (dacă creditoare)
    # 437 - Ajutor de șomaj (dacă creditoare)
    # 4411 - Impozit pe profit de plătit
    # 4423 - TVA de plată
    # 4428 - TVA neexigibilă (NU ESTE DATORIE)
    # 444 - Impozit pe venituri salariale de plată
    # 446 - Alte impozite și taxe
    # 447 - Fonduri speciale
    # 462 - Creditori diverși
    # 509 - Vărsăminte de efectuat pentru investiții financiare pe termen scurt
    # 512 - Credite bancare pe termen scurt (5191)
    "datorii_curente": {
        "debit": [],
        "credit": ["401", "403", "404", "408", "419", "421", "423", "424",
                   "426", "427", "4311", "4371", "4411", "4423", 
                   "444", "446", "447", "462", "509", "5191", "5192", "5198"]
    },

    # VENITURI (Clasa 7) - pentru calculul EBIT în Altman Z-Score
    # 70 - Venituri din vânzarea produselor
    # 71 - Venituri din vânzarea mărfurilor
    # 72 - Venituri din producția de imobilizări
    # 74 - Venituri din subvenții de exploatare
    # 75 - Alte venituri din exploatare
    # 709 - Reduceri comerciale acordate (se scade din venituri)
    # IMPORTANT: Folosim TOTCRED/TOTDEB (YTD - de la începutul anului) pentru că
    # conturile din clasa 7 se închid lunar în 121 (SOLD=0 după închidere)
    # RULCRED/RULDEB ar da doar valoarea lunară, nu YTD!
    "venituri": {
        "tot_credit": ["70", "701", "702", "703", "704", "705", "706", "707", "708",
                       "71", "72", "74", "75", "758"],
        "tot_debit": ["709"]  # Reduceri acordate clienților - funcționează INVERS
    },

    # CHELTUIELI OPERAȚIONALE (din Clasa 6, FĂRĂ 66x) - pentru calculul EBIT
    # 60 - Cheltuieli privind stocurile
    # 61 - Cheltuieli cu serviciile executate de terți
    # 62 - Cheltuieli cu alte servicii executate de terți
    # 63 - Cheltuieli cu alte impozite, taxe
    # 64 - Cheltuieli cu personalul
    # 65 - Alte cheltuieli de exploatare
    # 68 - Amortizări și provizioane (adăugat)
    # 609 - Reduceri comerciale primite (se scade din cheltuieli)
    # IMPORTANT: Folosim TOTDEB/TOTCRED (YTD - de la începutul anului) pentru că
    # conturile din clasa 6 se închid lunar în 121 (SOLD=0 după închidere)
    # RULDEB/RULCRED ar da doar valoarea lunară, nu YTD!
    "cheltuieli_operationale": {
        "tot_debit": ["60", "601", "602", "603", "604", "605", "606", "607", "608",
                      "61", "611", "612", "613", "614",
                      "62", "621", "622", "623", "624", "625", "626", "627", "628",
                      "63", "635",
                      "64", "641", "642", "643", "644", "645",
                      "65", "654", "658",
                      "68", "681", "686"],
        "tot_credit": ["609"]  # Reduceri primite de la furnizori - funcționează INVERS
    },

    # CHELTUIELI FINANCIARE (Clasa 66) - separat de cheltuieli operaționale
    # 661 - Cheltuieli privind titlurile de plasament cedate
    # 663 - Pierderi din creanțe legate de participații
    # 664 - Cheltuieli privind investițiile financiare cedate
    # 665 - Cheltuieli din diferențe de curs valutar
    # 666 - Cheltuieli privind dobânzile
    # 667 - Cheltuieli privind sconturile acordate
    # 668 - Alte cheltuieli financiare
    # IMPORTANT: Folosim TOTDEB (YTD - de la începutul anului) pentru că
    # conturile din clasa 6 se închid lunar în 121 (SOLD=0 după închidere)
    # RULDEB ar da doar valoarea lunară, nu YTD!
    "cheltuieli_financiare": {
        "tot_debit": ["66", "661", "663", "664", "665", "666", "667", "668"]
    },

    # CIFRA DE AFACERI (doar conturile 70x - venituri din vânzări)
    # Conform definiției oficiale, CA include DOAR venituri din vânzarea de bunuri și servicii
    # NU include:
    # - 71x (Variația stocurilor)
    # - 72x (Venituri din producția de imobilizări)
    # - 74x (Venituri din subvenții de exploatare)
    # - 75x (Alte venituri din exploatare)
    # - 76x (Venituri financiare)
    # Formula: TOTCRED(701-708) - TOTDEB(709 reduceri comerciale acordate)
    # IMPORTANT: Acesta este FĂRĂ TVA - TVA-ul merge în 4427, nu în 7xx
    "cifra_afaceri": {
        "tot_credit": ["701", "702", "703", "704", "705", "706", "707", "708"],
        "tot_debit": ["709"]  # Reduceri comerciale acordate (se scad)
    },

    # ACHIZIȚII STOCURI (Clasa 3 - intrări în stocuri FĂRĂ TVA)
    # Când cumpărăm: Debit 301/371 = Credit 401 → 301/371 DEBIT este FĂRĂ TVA
    # TVA-ul merge în 4426/4428, NU în contul de stoc
    # Aceasta evită complexitatea TVA la încasare, facturi nesosită, etc.
    # Include: materii prime (30x), materiale (31x, 32x), producție în curs (33x),
    # produse finite (34x), stocuri la terți (35x), animale (36x), mărfuri (37x), ambalaje (38x)
    "achizitii_stocuri": {
        "tot_debit": ["30", "301", "302", "303", "308",
                      "31", "311", "312",
                      "32", "321", "322", "323",
                      "33", "331", "332",
                      "34", "341", "345", "346", "348",
                      "35", "351", "354", "356", "357", "358",
                      "36", "361", "368",
                      "37", "371", "378",
                      "38", "381", "388"]
    }
}


class FinancialIndicatorsService:
    """
    Service pentru calculul indicatorilor financiari din balanța de verificare.

    Agregă soldurile din VBAL pe categorii de conturi pentru:
    - Active imobilizate
    - Stocuri
    - Creanțe
    - Disponibilități
    - Capital propriu
    - Rezultat
    - Datorii pe termen lung
    - Datorii curente
    - Venituri
    - Cheltuieli operaționale
    """

    @staticmethod
    @cached(cache_type='schema', key_params=['company_id', 'server_id'])
    async def _get_schema(company_id: int, server_id: Optional[str] = None) -> str:
        """
        Obține schema pentru company_id (CACHED PERMANENT)

        Schema este stocată permanent în cache deoarece nu se schimbă.
        """
        async with oracle_pool.get_connection(server_id) as connection:
            with connection.cursor() as cursor:
                schema_query = """
                    SELECT schema
                    FROM CONTAFIN_ORACLE.v_nom_firme
                    WHERE id_firma = :company_id
                """
                cursor.execute(schema_query, {'company_id': company_id})
                schema_result = cursor.fetchone()

                if not schema_result:
                    raise ValueError(f"Schema not found for company {company_id}")

                return schema_result[0]

    @staticmethod
    def _build_aggregate_case(prefixes: list[str], column: str) -> str:
        """
        Construiește expresie CASE pentru agregarea soldurilor pe prefixe de conturi.

        Args:
            prefixes: Lista de prefixe de conturi (ex: ["20", "21", "23"])
            column: Coloana de sumat (SOLDDEB sau SOLDCRED)

        Returns:
            Expresie SQL CASE pentru SUM
        """
        if not prefixes:
            return "0"

        conditions = " OR ".join([f"CONT LIKE '{prefix}%'" for prefix in prefixes])
        return f"SUM(CASE WHEN ({conditions}) THEN NVL({column}, 0) ELSE 0 END)"

    @staticmethod
    @cached(cache_type='fin_balance_sheet', key_params=['company_id', 'luna', 'an', 'server_id'])
    async def get_balance_sheet_aggregates(
        company_id: int,
        luna: int,
        an: int,
        server_id: Optional[str] = None
    ) -> BalanceSheetAggregates:
        """
        Obține soldurile agregate din balanța de verificare pentru calculul
        indicatorilor financiari (CACHED 30 min).

        Agregă soldurile din VBAL pe categorii de conturi folosind prefixe
        conform Planului de Conturi General (PCG) românesc.

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12)
            an: Anul contabil

        Returns:
            BalanceSheetAggregates cu soldurile agregate pentru fiecare categorie

        Raises:
            ValueError: Dacă schema nu este găsită pentru firma specificată
        """
        schema = await FinancialIndicatorsService._get_schema(company_id, server_id)

        async with oracle_pool.get_connection(server_id) as connection:
            with connection.cursor() as cursor:
                # Construim query-ul cu CASE pentru fiecare categorie
                # Soldurile din VBAL: SOLDDEB (sold debitor), SOLDCRED (sold creditor)
                #
                # Pentru active: valoarea = SOLDDEB - amortizări (SOLDCRED pentru 28, 29)
                # Pentru pasive: valoarea = SOLDCRED
                # Pentru venituri: valoarea = SOLDCRED (conturile de venituri sunt creditoare)
                # Pentru cheltuieli: valoarea = SOLDDEB (conturile de cheltuieli sunt debitoare)

                query = f"""
                    SELECT
                        -- ACTIVE IMOBILIZATE (brut - amortizări - ajustări)
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["active_imobilizate"]["debit"], "SOLDDEB"
                        )} -
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["active_imobilizate"]["credit"], "SOLDCRED"
                        )} as active_imobilizate,

                        -- STOCURI (brut - ajustări depreciere)
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["stocuri"]["debit"], "SOLDDEB"
                        )} -
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["stocuri"]["credit"], "SOLDCRED"
                        )} as stocuri,

                        -- CREANȚE (brut - ajustări depreciere)
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["creante"]["debit"], "SOLDDEB"
                        )} -
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["creante"]["credit"], "SOLDCRED"
                        )} as creante,

                        -- DISPONIBILITĂȚI
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["disponibilitati"]["debit"], "SOLDDEB"
                        )} as disponibilitati,

                        -- CAPITAL PROPRIU (sold creditor)
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["capital_propriu"]["credit"], "SOLDCRED"
                        )} as capital_propriu,

                        -- REZULTAT (credit - debit: profit dacă pozitiv, pierdere dacă negativ)
                        -- Conturile 107, 117, 121 pot avea sold fie debitor (pierdere) fie creditor (profit)
                        -- 129 (repartizare profit) este debitor și se scade
                        ({FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["rezultat"]["credit"], "SOLDCRED"
                        )} -
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["rezultat"]["debit"], "SOLDDEB"
                        )}) as rezultat,

                        -- DATORII TERMEN LUNG (sold creditor)
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["datorii_termen_lung"]["credit"], "SOLDCRED"
                        )} as datorii_termen_lung,

                        -- DATORII CURENTE (sold creditor)
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["datorii_curente"]["credit"], "SOLDCRED"
                        )} as datorii_curente,

                        -- VENITURI YTD (TOTCRED - TOTDEB pentru 709)
                        -- Folosim TOTCRED/TOTDEB pentru valori cumulate de la începutul anului
                        ({FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["venituri"]["tot_credit"], "TOTCRED"
                        )} -
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["venituri"]["tot_debit"], "TOTDEB"
                        )}) as venituri,

                        -- CHELTUIELI OPERAȚIONALE YTD (TOTDEB - TOTCRED pentru 609)
                        -- Folosim TOTDEB/TOTCRED pentru valori cumulate de la începutul anului
                        ({FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["cheltuieli_operationale"]["tot_debit"], "TOTDEB"
                        )} -
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["cheltuieli_operationale"]["tot_credit"], "TOTCRED"
                        )}) as cheltuieli_operationale,

                        -- CHELTUIELI FINANCIARE YTD (TOTDEB - Clasa 66)
                        -- Folosim TOTDEB pentru valori cumulate de la începutul anului
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["cheltuieli_financiare"]["tot_debit"], "TOTDEB"
                        )} as cheltuieli_financiare,

                        -- CAPITAL SOCIAL STRICT (sold creditor - doar contul 101)
                        -- Pentru calculul Rata ANC / Capital Social conform definiției legale stricte
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["capital_social_strict"]["credit"], "SOLDCRED"
                        )} as capital_social_strict,

                        -- CIFRA DE AFACERI YTD (doar 70x - venituri din vânzări, FĂRĂ TVA)
                        -- NU include: 71x variația stocurilor, 72x producție imobilizări,
                        -- 74x subvenții, 75x alte venituri
                        -- Formula: TOTCRED(701-708) - TOTDEB(709 reduceri comerciale acordate)
                        ({FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["cifra_afaceri"]["tot_credit"], "TOTCRED"
                        )} -
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["cifra_afaceri"]["tot_debit"], "TOTDEB"
                        )}) as cifra_afaceri,

                        -- ACHIZIȚII STOCURI YTD (Clasa 3 TOTDEB - intrări în stocuri, FĂRĂ TVA)
                        -- TVA-ul merge în 4426/4428, nu în conturile de stoc
                        {FinancialIndicatorsService._build_aggregate_case(
                            ACCOUNT_GROUPS["achizitii_stocuri"]["tot_debit"], "TOTDEB"
                        )} as achizitii_stocuri

                    FROM {schema}.VBAL
                    WHERE AN = :an
                      AND LUNA = :luna
                """

                params = {'an': an, 'luna': luna}
                cursor.execute(query, params)
                row = cursor.fetchone()

                if not row:
                    # Returnăm agregate cu valori zero dacă nu există date
                    logger.warning(
                        f"No VBAL data for company {company_id}, "
                        f"luna={luna}, an={an}"
                    )
                    return BalanceSheetAggregates(
                        company_id=company_id,
                        luna=luna,
                        an=an,
                        active_imobilizate=Decimal('0'),
                        stocuri=Decimal('0'),
                        creante=Decimal('0'),
                        disponibilitati=Decimal('0'),
                        capital_propriu=Decimal('0'),
                        rezultat=Decimal('0'),
                        datorii_termen_lung=Decimal('0'),
                        datorii_curente=Decimal('0'),
                        venituri=Decimal('0'),
                        cheltuieli_operationale=Decimal('0'),
                        cheltuieli_financiare=Decimal('0'),
                        capital_social_strict=Decimal('0'),
                        cifra_afaceri=Decimal('0'),
                        achizitii_stocuri=Decimal('0')
                    )

                # Construim modelul cu valorile agregate
                aggregates = BalanceSheetAggregates(
                    company_id=company_id,
                    luna=luna,
                    an=an,
                    active_imobilizate=Decimal(str(row[0] or 0)),
                    stocuri=Decimal(str(row[1] or 0)),
                    creante=Decimal(str(row[2] or 0)),
                    disponibilitati=Decimal(str(row[3] or 0)),
                    capital_propriu=Decimal(str(row[4] or 0)),
                    rezultat=Decimal(str(row[5] or 0)),
                    datorii_termen_lung=Decimal(str(row[6] or 0)),
                    datorii_curente=Decimal(str(row[7] or 0)),
                    venituri=Decimal(str(row[8] or 0)),
                    cheltuieli_operationale=Decimal(str(row[9] or 0)),
                    cheltuieli_financiare=Decimal(str(row[10] or 0)),
                    capital_social_strict=Decimal(str(row[11] or 0)),
                    cifra_afaceri=Decimal(str(row[12] or 0)),
                    achizitii_stocuri=Decimal(str(row[13] or 0))
                )

                logger.info(
                    f"Financial aggregates for company {company_id}, "
                    f"luna={luna}, an={an}: "
                    f"active_imobilizate={aggregates.active_imobilizate}, "
                    f"stocuri={aggregates.stocuri}, "
                    f"disponibilitati={aggregates.disponibilitati}, "
                    f"datorii_curente={aggregates.datorii_curente}, "
                    f"venituri={aggregates.venituri}, "
                    f"cheltuieli_op={aggregates.cheltuieli_operationale}, "
                    f"cifra_afaceri={aggregates.cifra_afaceri}, "
                    f"achizitii_stocuri={aggregates.achizitii_stocuri}"
                )

                # Warning: venituri/cheltuieli = 0 but balance sheet has data
                # This typically means VBAL doesn't have Class 6/7 data for this period
                # (accounting period may not be closed yet)
                has_balance_data = (
                    aggregates.active_imobilizate > 0 or
                    aggregates.disponibilitati > 0 or
                    aggregates.datorii_curente > 0
                )
                if has_balance_data and aggregates.venituri == 0 and aggregates.cheltuieli_operationale == 0:
                    logger.warning(
                        f"Company {company_id}, luna={luna}, an={an}: "
                        f"Balance sheet data exists but venituri/cheltuieli = 0. "
                        f"VBAL may not have Class 6/7 data for this period "
                        f"(accounting period not closed?)."
                    )

                return aggregates

    @staticmethod
    @cached(cache_type='fin_achizitii', key_params=['company_id', 'luna', 'an', 'server_id'])
    async def get_achizitii_ytd(
        company_id: int,
        luna: int,
        an: int,
        server_id: Optional[str] = None
    ) -> Decimal:
        """
        Calculează totalul achizițiilor YTD din Registrul Jurnal (ACT).

        Această metodă folosește tabelul ACT (înregistrări contabile) în loc de VBAL
        deoarece captează TOATE achizițiile:
        - Achiziții stocuri: 3x = 4x/46x (materii prime, mărfuri, materiale)
        - Achiziții directe: 6x = 4x/46x (servicii, consumabile pe cheltuieli)

        IMPORTANT: SUMA în tabelul ACT este ÎNTOTDEAUNA fără TVA!
        TVA-ul merge în conturi separate (4426, 4428).

        Formula:
        - (+) Intrări în stocuri/cheltuieli: SCD în 3x sau 6x, SCC în 4x sau 46x
        - (-) Discount/rabat primit: SCD în 40x, SCC în 667 sau 609

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12) - calcul YTD până la această lună
            an: Anul contabil

        Returns:
            Total achiziții YTD fără TVA (Decimal)
        """
        schema = await FinancialIndicatorsService._get_schema(company_id, server_id)

        async with oracle_pool.get_connection(server_id) as connection:
            with connection.cursor() as cursor:
                query = f"""
                    SELECT
                        NVL(SUM(CASE
                            WHEN (SCD LIKE '3%' OR SCD LIKE '6%')
                                 AND (SCC LIKE '4%' OR SCC LIKE '46%')
                            THEN SUMA
                            ELSE 0
                        END), 0)
                        -
                        NVL(SUM(CASE
                            WHEN SCD LIKE '40%' AND (SCC = '667' OR SCC = '609')
                            THEN SUMA
                            ELSE 0
                        END), 0) as achizitii_ytd
                    FROM {schema}.ACT
                    WHERE AN = :an
                      AND LUNA <= :luna
                      AND NVL(STERS, 0) = 0
                """
                cursor.execute(query, {'an': an, 'luna': luna})
                row = cursor.fetchone()

                achizitii_total = Decimal(str(row[0] or 0))

                logger.info(
                    f"Achiziții YTD from ACT for company {company_id}, "
                    f"luna<={luna}, an={an}: {achizitii_total}"
                )

                return achizitii_total

    @staticmethod
    @cached(cache_type='fin_cashflow_vbal', key_params=['company_id', 'luna', 'an', 'server_id'])
    async def get_cashflow_from_vbal(
        company_id: int,
        luna: int,
        an: int,
        server_id: Optional[str] = None
    ) -> dict:
        """
        Calculează datele de Cash Flow direct din VBAL (balanța de verificare).

        Aceasta este sursa preferată pentru Cash Flow, în loc de vbalanta_parteneri,
        pentru consistență cu celelalte calcule de indicatori.

        IMPORTANT: Cash Flow INCLUDE TVA deoarece măsoară fluxuri reale de numerar.
        Când clientul plătește 1.190 RON, primim 1.190 RON (nu 1.000).

        Coloane VBAL utilizate:
        - RULCRED/RULDEB: Rulaj lunar (mișcări în luna curentă)
        - TOTCRED/TOTDEB: Total YTD (de la 1 ianuarie până la luna curentă)

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12)
            an: Anul contabil

        Returns:
            Dict cu:
            - incasari_luna: Încasări lunare (4111+461 RULCRED)
            - plati_luna: Plăți lunare (401+404+462 RULDEB)
            - incasari_ytd: Încasări YTD (4111+461 TOTCRED)
            - plati_ytd: Plăți YTD (401+404+462 TOTDEB)
        """
        schema = await FinancialIndicatorsService._get_schema(company_id, server_id)

        async with oracle_pool.get_connection(server_id) as connection:
            with connection.cursor() as cursor:
                query = f"""
                    SELECT
                        -- Încasări luna curentă (4111+461 RULCRED)
                        -- Credit pe 4111 = client plătește
                        NVL(SUM(CASE
                            WHEN CONT IN ('4111', '461') THEN RULCRED
                            ELSE 0
                        END), 0) as incasari_luna,

                        -- Plăți luna curentă (401+404+462 RULDEB)
                        -- Debit pe 401 = plătim furnizorul
                        NVL(SUM(CASE
                            WHEN CONT IN ('401', '404', '462') THEN RULDEB
                            ELSE 0
                        END), 0) as plati_luna,

                        -- Încasări YTD (4111+461 TOTCRED)
                        NVL(SUM(CASE
                            WHEN CONT IN ('4111', '461') THEN TOTCRED
                            ELSE 0
                        END), 0) as incasari_ytd,

                        -- Plăți YTD (401+404+462 TOTDEB)
                        NVL(SUM(CASE
                            WHEN CONT IN ('401', '404', '462') THEN TOTDEB
                            ELSE 0
                        END), 0) as plati_ytd

                    FROM {schema}.VBAL
                    WHERE AN = :an AND LUNA = :luna
                """
                cursor.execute(query, {'an': an, 'luna': luna})
                row = cursor.fetchone()

                result = {
                    'incasari_luna': Decimal(str(row[0] or 0)),
                    'plati_luna': Decimal(str(row[1] or 0)),
                    'incasari_ytd': Decimal(str(row[2] or 0)),
                    'plati_ytd': Decimal(str(row[3] or 0))
                }

                logger.info(
                    f"Cash flow from VBAL for company {company_id}, "
                    f"luna={luna}, an={an}: "
                    f"incasari_luna={result['incasari_luna']}, "
                    f"plati_luna={result['plati_luna']}, "
                    f"incasari_ytd={result['incasari_ytd']}, "
                    f"plati_ytd={result['plati_ytd']}"
                )

                return result

    @staticmethod
    def _calculate_indicator_status(
        value: float,
        good_threshold: float,
        warning_threshold: float,
        higher_is_better: bool = True
    ) -> str:
        """
        Determină statusul unui indicator pe baza pragurilor.

        Args:
            value: Valoarea indicatorului
            good_threshold: Pragul pentru status 'good'
            warning_threshold: Pragul pentru status 'warning'
            higher_is_better: True dacă valori mai mari sunt mai bune

        Returns:
            Status: 'good', 'warning', sau 'danger'
        """
        if higher_is_better:
            if value >= good_threshold:
                return "good"
            elif value >= warning_threshold:
                return "warning"
            else:
                return "danger"
        else:
            # Pentru indicatori unde valori mai mici sunt mai bune (ex: DSO)
            if value <= good_threshold:
                return "good"
            elif value <= warning_threshold:
                return "warning"
            else:
                return "danger"

    @staticmethod
    async def calculate_liquidity_indicators(
        company_id: int,
        luna: int,
        an: int,
        server_id: Optional[str] = None
    ) -> LiquidityIndicators:
        """
        Calculează indicatorii de lichiditate pentru evaluarea capacității
        de plată a datoriilor pe termen scurt.

        Indicatori calculați:
        - Lichiditate curentă (Current Ratio) = active_curente / datorii_curente
        - Lichiditate imediată (Quick Ratio) = (disponibilități + creanțe) / datorii_curente
        - Lichiditate la vedere (Cash Ratio) = disponibilități / datorii_curente

        Praguri de referință (conform standardelor bancare):
        - Lichiditate curentă: good >= 2.0, warning 1.0-2.0, danger < 1.0
        - Lichiditate imediată: good >= 1.0, warning 0.5-1.0, danger < 0.5
        - Lichiditate la vedere: good >= 0.2, warning 0.1-0.2, danger < 0.1

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12)
            an: Anul contabil

        Returns:
            LiquidityIndicators cu cele trei rate de lichiditate
        """
        # Obținem agregatele din balanță
        aggregates = await FinancialIndicatorsService.get_balance_sheet_aggregates(
            company_id, luna, an, server_id
        )
        # Ensure aggregates is a BalanceSheetAggregates model (cache may return dict)
        if isinstance(aggregates, dict):
            aggregates = BalanceSheetAggregates(**aggregates)

        # Calculăm active curente (stocuri + creanțe + disponibilități)
        active_curente = float(aggregates.active_curente)
        disponibilitati = float(aggregates.disponibilitati)
        creante = float(aggregates.creante)
        datorii_curente = float(aggregates.datorii_curente)

        # Handle cazul special: datorii_curente = 0
        if datorii_curente == 0:
            # Compania nu are datorii pe termen scurt - situație excelentă
            # Returnăm None pentru valoare dar status "good" cu mesaj explicativ
            no_debt_message = "Fără datorii curente - lichiditate maximă"

            return LiquidityIndicators(
                lichiditate_curenta=IndicatorResult(
                    value=None,
                    status="good",
                    threshold_min=2.0,
                    threshold_max=None,
                    message=no_debt_message
                ),
                lichiditate_imediata=IndicatorResult(
                    value=None,
                    status="good",
                    threshold_min=1.0,
                    threshold_max=None,
                    message=no_debt_message
                ),
                lichiditate_vedere=IndicatorResult(
                    value=None,
                    status="good",
                    threshold_min=0.2,
                    threshold_max=None,
                    message=no_debt_message
                ),
                # Sub-indicatori pentru verificare manuală în balanță
                active_curente=IndicatorResult(
                    value=round(active_curente, 2),
                    status="good",
                    message="Stocuri + Creanțe + Disponibilități"
                ),
                disponibilitati=IndicatorResult(
                    value=round(disponibilitati, 2),
                    status="good",
                    message="Bancă (512x) + Casă (531x)"
                ),
                creante=IndicatorResult(
                    value=round(creante, 2),
                    status="good",
                    message="Clienți (411x) + Debitori (461x)"
                ),
                datorii_curente=IndicatorResult(
                    value=0,
                    status="good",
                    message="Fără datorii pe termen scurt"
                )
            )

        # Calculăm ratele de lichiditate
        # 1. Lichiditate curentă (Current Ratio)
        lichiditate_curenta_val = active_curente / datorii_curente
        lichiditate_curenta_status = FinancialIndicatorsService._calculate_indicator_status(
            lichiditate_curenta_val,
            good_threshold=2.0,
            warning_threshold=1.0
        )

        # 2. Lichiditate imediată (Quick Ratio)
        # Exclude stocurile - măsoară lichiditatea "rapidă"
        lichiditate_imediata_val = (disponibilitati + creante) / datorii_curente
        lichiditate_imediata_status = FinancialIndicatorsService._calculate_indicator_status(
            lichiditate_imediata_val,
            good_threshold=1.0,
            warning_threshold=0.5
        )

        # 3. Lichiditate la vedere (Cash Ratio)
        # Doar disponibilități - lichiditatea imediată
        lichiditate_vedere_val = disponibilitati / datorii_curente
        lichiditate_vedere_status = FinancialIndicatorsService._calculate_indicator_status(
            lichiditate_vedere_val,
            good_threshold=0.2,
            warning_threshold=0.1
        )

        # Rotunjim valorile la 2 zecimale pentru afișare
        result = LiquidityIndicators(
            lichiditate_curenta=IndicatorResult(
                value=round(lichiditate_curenta_val, 2),
                status=lichiditate_curenta_status,
                threshold_min=2.0,
                threshold_max=None
            ),
            lichiditate_imediata=IndicatorResult(
                value=round(lichiditate_imediata_val, 2),
                status=lichiditate_imediata_status,
                threshold_min=1.0,
                threshold_max=None
            ),
            lichiditate_vedere=IndicatorResult(
                value=round(lichiditate_vedere_val, 2),
                status=lichiditate_vedere_status,
                threshold_min=0.2,
                threshold_max=None
            ),
            # Sub-indicatori pentru verificare manuală în balanță
            active_curente=IndicatorResult(
                value=round(active_curente, 2),
                status="good",
                message="Stocuri + Creanțe + Disponibilități"
            ),
            disponibilitati=IndicatorResult(
                value=round(disponibilitati, 2),
                status="good",
                message="Bancă (512x) + Casă (531x)"
            ),
            creante=IndicatorResult(
                value=round(creante, 2),
                status="good",
                message="Clienți (411x) + Debitori (461x)"
            ),
            datorii_curente=IndicatorResult(
                value=round(datorii_curente, 2),
                status="good",
                message="Furnizori + TVA + Salarii etc."
            )
        )

        logger.info(
            f"Liquidity indicators for company {company_id}, luna={luna}, an={an}: "
            f"curenta={result.lichiditate_curenta.value} ({result.lichiditate_curenta.status}), "
            f"imediata={result.lichiditate_imediata.value} ({result.lichiditate_imediata.status}), "
            f"vedere={result.lichiditate_vedere.value} ({result.lichiditate_vedere.status})"
        )

        return result

    @staticmethod
    @cached(cache_type='fin_efficiency', key_params=['company_id', 'luna', 'an', 'server_id'])
    async def calculate_efficiency_indicators(
        company_id: int,
        luna: int,
        an: int,
        server_id: Optional[str] = None
    ) -> EfficiencyIndicators:
        """
        Calculează indicatorii de eficiență pentru evaluarea vitezei de conversie
        a resurselor în numerar.

        Indicatori calculați:
        - DSO (Days Sales Outstanding) = (clienti_sold / facturari_lunare) * 30
        - DPO (Days Payables Outstanding) = (furnizori_sold / achizitii_lunare) * 30
        - Cash Conversion Cycle = DSO - DPO
        - Rata încasare = incasari / facturari * 100
        - Rata plată = plati / achizitii * 100

        Praguri de referință pentru DSO:
        - Good: < 30 zile (încasare rapidă)
        - Warning: 30-45 zile (încasare moderată)
        - Danger: > 45 zile (încasare lentă - risc de cash flow)

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12)
            an: Anul contabil

        Returns:
            EfficiencyIndicators cu cele cinci rate de eficiență
        """
        # Import DashboardService here to avoid circular imports
        from .dashboard_service import DashboardService

        # Obținem datele din summary (solduri clienți/furnizori)
        summary = await DashboardService.get_complete_summary(
            company=str(company_id),
            username="system",  # System call for indicators
            luna=luna,
            an=an,
            server_id=server_id
        )
        # Ensure summary is a DashboardSummary model (cache may return dict)
        if isinstance(summary, dict):
            summary = DashboardSummary(**summary)

        # Obținem datele din trends (facturări/încasări/achiziții/plăți lunare)
        trends = await DashboardService.get_trends(
            company_id=company_id,
            period='12m',  # Ultimele 12 luni pentru media lunară
            server_id=server_id
        )

        # Extragem soldurile din summary
        clienti_sold = float(summary.clienti_sold_total)
        furnizori_sold = float(summary.furnizori_sold_total)

        # Extragem datele lunare din trends
        # Folosim ultima lună disponibilă pentru facturări/încasări/achiziții/plăți
        clienti_facturat = trends.get("clienti_facturat", [])
        clienti_incasat = trends.get("clienti_incasat", [])
        furnizori_facturat = trends.get("furnizori_facturat", [])
        furnizori_achitat = trends.get("furnizori_achitat", [])

        # Calculăm media lunară (pentru stabilitate) sau folosim ultima lună
        # Pentru DSO/DPO, folosim media ultimelor 3 luni pentru a evita fluctuații
        def safe_avg(values: list, n: int = 3) -> float:
            """Calculează media ultimelor n valori, sau toate dacă sunt mai puține"""
            if not values:
                return 0
            recent = values[-n:] if len(values) >= n else values
            return sum(recent) / len(recent) if recent else 0

        facturari_lunare = safe_avg(clienti_facturat)
        incasari_lunare = safe_avg(clienti_incasat)
        achizitii_lunare = safe_avg(furnizori_facturat)
        plati_lunare = safe_avg(furnizori_achitat)

        # Calculăm indicatorii

        # 1. DSO (Days Sales Outstanding) - Durata medie de încasare
        # Formula: (clienti_sold / facturari_lunare) * 30
        if facturari_lunare > 0:
            dso_val = (clienti_sold / facturari_lunare) * 30
            dso_status = FinancialIndicatorsService._calculate_indicator_status(
                dso_val,
                good_threshold=30,
                warning_threshold=45,
                higher_is_better=False  # Pentru DSO, mai mic e mai bine
            )
            dso = IndicatorResult(
                value=round(dso_val, 1),
                status=dso_status,
                threshold_min=None,
                threshold_max=30  # Good if <= 30 days
            )
        else:
            dso = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=None,
                threshold_max=30,
                message="Fără facturări în perioada analizată"
            )

        # 2. DPO (Days Payables Outstanding) - Durata medie de plată
        # Formula: (furnizori_sold / achizitii_lunare) * 30
        if achizitii_lunare > 0:
            dpo_val = (furnizori_sold / achizitii_lunare) * 30
            # Pentru DPO nu avem praguri stricte - depinde de strategia firmei
            # Un DPO mai mare înseamnă că folosim creditul furnizorilor
            dpo = IndicatorResult(
                value=round(dpo_val, 1),
                status="good",  # DPO nu are praguri de "danger"
                threshold_min=None,
                threshold_max=None,
                message="Durata medie de plată furnizori"
            )
        else:
            dpo = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=None,
                threshold_max=None,
                message="Fără achiziții în perioada analizată"
            )

        # 3. Cash Conversion Cycle = DSO - DPO
        # Negativ = firma se finanțează din creditul furnizorilor (favorabil)
        # Pozitiv = cash blocat în ciclul de afaceri
        if dso.value is not None and dpo.value is not None:
            ccc_val = dso.value - dpo.value
            # CCC negativ e bun (ne finanțăm din creditul furnizorilor)
            ccc_status = FinancialIndicatorsService._calculate_indicator_status(
                ccc_val,
                good_threshold=0,
                warning_threshold=15,
                higher_is_better=False
            )
            ccc_message = (
                "Ciclu negativ = finanțare din creditul furnizorilor"
                if ccc_val < 0
                else "Numerar blocat în ciclul de afaceri"
            )
            cash_conversion_cycle = IndicatorResult(
                value=round(ccc_val, 1),
                status=ccc_status,
                threshold_min=None,
                threshold_max=0,
                message=ccc_message
            )
        else:
            cash_conversion_cycle = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=None,
                threshold_max=0,
                message="Nu se poate calcula - lipsesc date DSO/DPO"
            )

        # 4. Rata încasare = incasari / facturari * 100
        # Calculăm pentru perioada YTD din trends (suma totală)
        total_facturari = sum(clienti_facturat) if clienti_facturat else 0
        total_incasari = sum(clienti_incasat) if clienti_incasat else 0

        if total_facturari > 0:
            rata_incasare_val = (total_incasari / total_facturari) * 100
            rata_incasare_status = FinancialIndicatorsService._calculate_indicator_status(
                rata_incasare_val,
                good_threshold=95,
                warning_threshold=80
            )
            rata_incasare = IndicatorResult(
                value=round(rata_incasare_val, 1),
                status=rata_incasare_status,
                threshold_min=95,
                threshold_max=None
            )
        else:
            rata_incasare = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=95,
                threshold_max=None,
                message="Fără facturări în perioada analizată"
            )

        # 5. Rata plată = plati / achizitii * 100
        total_achizitii = sum(furnizori_facturat) if furnizori_facturat else 0
        total_plati = sum(furnizori_achitat) if furnizori_achitat else 0

        if total_achizitii > 0:
            rata_plata_val = (total_plati / total_achizitii) * 100
            # Pentru rata de plată, nu există "danger" - depinde de strategia firmei
            rata_plata = IndicatorResult(
                value=round(rata_plata_val, 1),
                status="good",  # Informativ, fără praguri stricte
                threshold_min=None,
                threshold_max=None
            )
        else:
            rata_plata = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=None,
                threshold_max=None,
                message="Fără achiziții în perioada analizată"
            )

        result = EfficiencyIndicators(
            dso=dso,
            dpo=dpo,
            cash_conversion_cycle=cash_conversion_cycle,
            rata_incasare=rata_incasare,
            rata_plata=rata_plata,
            # Sub-indicatori pentru verificare manuală
            sold_clienti=IndicatorResult(
                value=round(clienti_sold, 2),
                status="good",
                message="Sold Clienți la final de lună"
            ),
            facturari_lunare=IndicatorResult(
                value=round(facturari_lunare, 2),
                status="good",
                message="Media facturărilor lunare (3 luni)"
            ),
            sold_furnizori=IndicatorResult(
                value=round(furnizori_sold, 2),
                status="good",
                message="Sold Furnizori la final de lună"
            ),
            achizitii_lunare=IndicatorResult(
                value=round(achizitii_lunare, 2),
                status="good",
                message="Media achizițiilor lunare (3 luni)"
            ),
            incasari_luna=IndicatorResult(
                value=round(incasari_lunare, 2),
                status="good",
                message="Media încasărilor lunare (3 luni)"
            ),
            plati_luna=IndicatorResult(
                value=round(plati_lunare, 2),
                status="good",
                message="Media plăților lunare (3 luni)"
            )
        )

        logger.info(
            f"Efficiency indicators for company {company_id}, luna={luna}, an={an}: "
            f"DSO={dso.value} ({dso.status}), "
            f"DPO={dpo.value}, "
            f"CCC={cash_conversion_cycle.value} ({cash_conversion_cycle.status}), "
            f"rata_incasare={rata_incasare.value}% ({rata_incasare.status})"
        )

        return result

    @staticmethod
    @cached(cache_type='fin_risk', key_params=['company_id', 'luna', 'an', 'server_id'])
    async def calculate_risk_indicators(
        company_id: int,
        luna: int,
        an: int,
        server_id: Optional[str] = None
    ) -> RiskIndicators:
        """
        Calculează indicatorii de risc și aging pentru evaluarea sănătății
        portofoliului de creanțe și datorii.

        Indicatori calculați:
        - creante_restante_pct: Procentul creanțelor restante din total clienți
          Formula: clienti_sold_restant / clienti_sold_total * 100
          Good: < 20%, Warning: 20-30%, Danger: > 30%

        - creante_90plus_pct: Procentul creanțelor restante > 90 zile din total
          Formula: clienti_restant_90plus / clienti_sold_total * 100
          Good: < 5%, Warning: 5-10%, Danger: > 10%

        - datorii_restante_pct: Procentul datoriilor restante din total furnizori
          Formula: furnizori_sold_restant / furnizori_sold_total * 100
          Good: < 10%, Warning: 10-20%, Danger: > 20%

        - raport_datorii_trezorerie: Raportul între datorii furnizori și trezorerie
          Formula: furnizori_sold_total / trezorerie
          Good: < 2, Warning: 2-4, Danger: > 4

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12)
            an: Anul contabil

        Returns:
            RiskIndicators cu cei patru indicatori de risc
        """
        # Import DashboardService here to avoid circular imports
        from .dashboard_service import DashboardService

        # Obținem datele din summary (solduri clienți/furnizori/aging)
        summary = await DashboardService.get_complete_summary(
            company=str(company_id),
            username="system",  # System call for indicators
            luna=luna,
            an=an,
            server_id=server_id
        )
        # Ensure summary is a DashboardSummary model (cache may return dict)
        if isinstance(summary, dict):
            summary = DashboardSummary(**summary)

        # Extragem soldurile din summary
        clienti_sold_total = float(summary.clienti_sold_total)
        clienti_sold_restant = float(summary.clienti_sold_restant)
        clienti_restant_90plus = float(summary.clienti_restant_90plus)
        furnizori_sold_total = float(summary.furnizori_sold_total)
        furnizori_sold_restant = float(summary.furnizori_sold_restant)

        # Calculăm trezoreria totală din treasury_totals_by_currency (sumă pe toate valutele)
        trezorerie = sum(float(v) for v in summary.treasury_totals_by_currency.values())

        # 1. Creanțe restante % - procentul din solduri clienți care sunt restante
        if clienti_sold_total > 0:
            creante_restante_val = (clienti_sold_restant / clienti_sold_total) * 100
            creante_restante_status = FinancialIndicatorsService._calculate_indicator_status(
                creante_restante_val,
                good_threshold=20,
                warning_threshold=30,
                higher_is_better=False  # Mai mic e mai bine
            )
            creante_restante_pct = IndicatorResult(
                value=round(creante_restante_val, 1),
                status=creante_restante_status,
                threshold_min=None,
                threshold_max=20
            )
        else:
            creante_restante_pct = IndicatorResult(
                value=None,
                status="good",
                threshold_min=None,
                threshold_max=20,
                message="Fără sold clienți"
            )

        # 2. Creanțe 90+ zile % - creanțe cu risc mare de nerecuperare
        if clienti_sold_total > 0:
            creante_90plus_val = (clienti_restant_90plus / clienti_sold_total) * 100
            creante_90plus_status = FinancialIndicatorsService._calculate_indicator_status(
                creante_90plus_val,
                good_threshold=5,
                warning_threshold=10,
                higher_is_better=False  # Mai mic e mai bine
            )
            creante_90plus_pct = IndicatorResult(
                value=round(creante_90plus_val, 1),
                status=creante_90plus_status,
                threshold_min=None,
                threshold_max=5
            )
        else:
            creante_90plus_pct = IndicatorResult(
                value=None,
                status="good",
                threshold_min=None,
                threshold_max=5,
                message="Fără sold clienți"
            )

        # 3. Datorii restante % - procentul din solduri furnizori care sunt restante
        if furnizori_sold_total > 0:
            datorii_restante_val = (furnizori_sold_restant / furnizori_sold_total) * 100
            datorii_restante_status = FinancialIndicatorsService._calculate_indicator_status(
                datorii_restante_val,
                good_threshold=10,
                warning_threshold=20,
                higher_is_better=False  # Mai mic e mai bine
            )
            datorii_restante_pct = IndicatorResult(
                value=round(datorii_restante_val, 1),
                status=datorii_restante_status,
                threshold_min=None,
                threshold_max=10
            )
        else:
            datorii_restante_pct = IndicatorResult(
                value=None,
                status="good",
                threshold_min=None,
                threshold_max=10,
                message="Fără sold furnizori"
            )

        # 4. Raport datorii/trezorerie - câte unități de cash trebuie pentru a plăti furnizorii
        if trezorerie > 0:
            raport_val = furnizori_sold_total / trezorerie
            raport_status = FinancialIndicatorsService._calculate_indicator_status(
                raport_val,
                good_threshold=2,
                warning_threshold=4,
                higher_is_better=False  # Mai mic e mai bine (mai puțin datorie per cash)
            )
            raport_message = (
                "Trezorerie suficientă pentru acoperirea datoriilor"
                if raport_val < 2
                else "Trezorerie insuficientă pentru datorii"
                if raport_val > 4
                else "Trezorerie moderată pentru datorii"
            )
            raport_datorii_trezorerie = IndicatorResult(
                value=round(raport_val, 2),
                status=raport_status,
                threshold_min=None,
                threshold_max=2,
                message=raport_message
            )
        elif furnizori_sold_total == 0:
            # Fără datorii furnizori - situație bună
            raport_datorii_trezorerie = IndicatorResult(
                value=0,
                status="good",
                threshold_min=None,
                threshold_max=2,
                message="Fără datorii furnizori"
            )
        else:
            # Trezorerie 0 dar avem datorii - situație critică
            raport_datorii_trezorerie = IndicatorResult(
                value=None,
                status="danger",
                threshold_min=None,
                threshold_max=2,
                message="Trezorerie zero - nu se poate acoperi datoriile"
            )

        result = RiskIndicators(
            creante_restante_pct=creante_restante_pct,
            creante_90plus_pct=creante_90plus_pct,
            datorii_restante_pct=datorii_restante_pct,
            raport_datorii_trezorerie=raport_datorii_trezorerie,
            # Sub-indicatori pentru verificare manuală
            total_clienti=IndicatorResult(
                value=round(clienti_sold_total, 2),
                status="good",
                message="Sold total clienți (411x)"
            ),
            clienti_restanti=IndicatorResult(
                value=round(clienti_sold_restant, 2),
                status="good",
                message="Clienți cu facturi restante"
            ),
            clienti_90plus=IndicatorResult(
                value=round(clienti_restant_90plus, 2),
                status="good",
                message="Clienți restant >90 zile"
            ),
            total_furnizori=IndicatorResult(
                value=round(furnizori_sold_total, 2),
                status="good",
                message="Sold total furnizori (401x)"
            ),
            furnizori_restanti=IndicatorResult(
                value=round(furnizori_sold_restant, 2),
                status="good",
                message="Furnizori cu facturi restante"
            ),
            trezorerie=IndicatorResult(
                value=round(trezorerie, 2),
                status="good",
                message="Disponibilități (512x + 531x)"
            )
        )

        logger.info(
            f"Risk indicators for company {company_id}, luna={luna}, an={an}: "
            f"creante_restante={creante_restante_pct.value}% ({creante_restante_pct.status}), "
            f"creante_90plus={creante_90plus_pct.value}% ({creante_90plus_pct.status}), "
            f"datorii_restante={datorii_restante_pct.value}% ({datorii_restante_pct.status}), "
            f"raport_datorii_trez={raport_datorii_trezorerie.value} ({raport_datorii_trezorerie.status})"
        )

        return result

    @staticmethod
    @cached(cache_type='fin_cashflow', key_params=['company_id', 'luna', 'an', 'server_id'])
    async def calculate_cashflow_indicators(
        company_id: int,
        luna: int,
        an: int,
        server_id: Optional[str] = None
    ) -> CashFlowIndicators:
        """
        Calculează indicatorii de cash flow pentru evaluarea generării și
        consumului de numerar.

        Indicatori calculați:
        - flux_net_lunar: Încasări luna - plăți luna (fluxul net de numerar lunar)
          Good: > 0 (firma generează numerar), Danger: < 0 (firma consumă numerar)

        - cash_flow_ytd: Suma fluxurilor nete de la ianuarie până la luna curentă
          Arată tendința generală a anului în curs

        - flux_net_yoy_pct: Variația procentuală an-la-an
          Formula: (cf_curent - cf_anterior) / abs(cf_anterior) * 100

        - acoperire_cash_flow: Cash flow YTD / datorii restante
          Good: > 1 (cash flow suficient), Warning: 0.5-1, Danger: < 0.5

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12)
            an: Anul contabil

        Returns:
            CashFlowIndicators cu cei patru indicatori de cash flow
        """
        # Import DashboardService here to avoid circular imports (for datorii restante)
        from .dashboard_service import DashboardService

        # Obținem datele de cash flow din VBAL (sursa preferată)
        # VBAL oferă date directe: RULCRED/RULDEB pentru lunar, TOTCRED/TOTDEB pentru YTD
        cf_data_curent = await FinancialIndicatorsService.get_cashflow_from_vbal(
            company_id, luna, an, server_id
        )
        cf_data_anterior = await FinancialIndicatorsService.get_cashflow_from_vbal(
            company_id, luna, an - 1, server_id
        )

        # Obținem datele din summary pentru datorii restante
        summary = await DashboardService.get_complete_summary(
            company=str(company_id),
            username="system",
            luna=luna,
            an=an,
            server_id=server_id
        )
        # Ensure summary is a DashboardSummary model (cache may return dict)
        if isinstance(summary, dict):
            summary = DashboardSummary(**summary)

        # Calculăm valorile de cash flow din VBAL
        # Flux net lunar = încasări luna - plăți luna (RULCRED - RULDEB)
        incasari_luna = float(cf_data_curent['incasari_luna'])
        plati_luna = float(cf_data_curent['plati_luna'])
        flux_net_val = incasari_luna - plati_luna

        # Cash flow YTD = încasări YTD - plăți YTD (TOTCRED - TOTDEB)
        incasari_ytd = float(cf_data_curent['incasari_ytd'])
        plati_ytd = float(cf_data_curent['plati_ytd'])
        cf_ytd_val = incasari_ytd - plati_ytd

        # Cash flow YTD an anterior (pentru comparație YoY)
        incasari_ytd_prev = float(cf_data_anterior['incasari_ytd'])
        plati_ytd_prev = float(cf_data_anterior['plati_ytd'])
        cf_ytd_anterior = incasari_ytd_prev - plati_ytd_prev

        # 1. Flux net lunar
        flux_net_status = "good" if flux_net_val > 0 else "danger"
        flux_net_message = (
            "Firma generează numerar"
            if flux_net_val > 0
            else "Firma consumă numerar"
        )
        flux_net_lunar = IndicatorResult(
            value=round(flux_net_val, 2),
            status=flux_net_status,
            threshold_min=0,
            threshold_max=None,
            message=flux_net_message
        )

        # 2. Cash flow YTD (încasări YTD - plăți YTD din VBAL TOTCRED/TOTDEB)
        cf_ytd_status = "good" if cf_ytd_val > 0 else "danger"
        cash_flow_ytd = IndicatorResult(
            value=round(cf_ytd_val, 2),
            status=cf_ytd_status,
            threshold_min=0,
            threshold_max=None
        )

        # 3. Flux net YoY % (variația an-la-an)
        # Comparăm cash flow-ul YTD curent cu cel din aceeași perioadă a anului anterior
        if abs(cf_ytd_anterior) > 0:
            yoy_pct = ((cf_ytd_val - cf_ytd_anterior) / abs(cf_ytd_anterior)) * 100
            yoy_status = "good" if yoy_pct >= 0 else "danger"
            yoy_message = (
                "Creștere cash flow față de anul anterior"
                if yoy_pct >= 0
                else "Scădere cash flow față de anul anterior"
            )
            flux_net_yoy_pct = IndicatorResult(
                value=round(yoy_pct, 1),
                status=yoy_status,
                threshold_min=0,
                threshold_max=None,
                message=yoy_message
            )
        else:
            # Cash flow anterior era zero
            if cf_ytd_val > 0:
                flux_net_yoy_pct = IndicatorResult(
                    value=100.0,
                    status="good",
                    threshold_min=0,
                    threshold_max=None,
                    message="Cash flow pozitiv vs zero anul anterior"
                )
            elif cf_ytd_val < 0:
                flux_net_yoy_pct = IndicatorResult(
                    value=-100.0,
                    status="danger",
                    threshold_min=0,
                    threshold_max=None,
                    message="Cash flow negativ vs zero anul anterior"
                )
            else:
                flux_net_yoy_pct = IndicatorResult(
                    value=0.0,
                    status="warning",
                    threshold_min=0,
                    threshold_max=None,
                    message="Cash flow zero în ambii ani"
                )

        # 4. Acoperire cash flow = cash_flow_ytd / datorii_restante
        # Datoriile restante sunt furnizori_sold_restant din summary
        datorii_restante = float(summary.furnizori_sold_restant)

        if datorii_restante > 0 and cf_ytd_val is not None:
            acoperire_val = cf_ytd_val / datorii_restante
            acoperire_status = FinancialIndicatorsService._calculate_indicator_status(
                acoperire_val,
                good_threshold=1.0,
                warning_threshold=0.5
            )
            acoperire_message = (
                "Cash flow suficient pentru acoperirea datoriilor restante"
                if acoperire_val >= 1.0
                else "Cash flow insuficient pentru acoperirea datoriilor restante"
                if acoperire_val < 0.5
                else "Cash flow parțial pentru datorii restante"
            )
            acoperire_cash_flow = IndicatorResult(
                value=round(acoperire_val, 2),
                status=acoperire_status,
                threshold_min=1.0,
                threshold_max=None,
                message=acoperire_message
            )
        elif datorii_restante == 0:
            # Fără datorii restante - situație excelentă
            acoperire_cash_flow = IndicatorResult(
                value=None,
                status="good",
                threshold_min=1.0,
                threshold_max=None,
                message="Fără datorii restante - nu este nevoie de acoperire"
            )
        else:
            # Nu avem date de cash flow
            acoperire_cash_flow = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=1.0,
                threshold_max=None,
                message="Nu se poate calcula acoperirea cash flow"
            )

        # Sub-indicatori pentru verificare manuală
        # NOTA: incasari_luna și plati_luna sunt calculate mai sus din VBAL (liniile 1442-1443)
        # cf_ytd_anterior este calculat mai sus din VBAL (linia 1454)

        result = CashFlowIndicators(
            flux_net_lunar=flux_net_lunar,
            cash_flow_ytd=cash_flow_ytd,
            flux_net_yoy_pct=flux_net_yoy_pct,
            acoperire_cash_flow=acoperire_cash_flow,
            # Sub-indicatori pentru verificare manuală (din VBAL)
            incasari_luna=IndicatorResult(
                value=round(incasari_luna, 2),
                status="good",
                message="Încasări luna curentă (4111+461 RULCRED)"
            ),
            plati_luna=IndicatorResult(
                value=round(plati_luna, 2),
                status="good",
                message="Plăți luna curentă (401+404+462 RULDEB)"
            ),
            cf_an_precedent=IndicatorResult(
                value=round(cf_ytd_anterior, 2),
                status="good",
                message="Cash Flow YTD an precedent (din VBAL)"
            ),
            datorii_restante=IndicatorResult(
                value=round(datorii_restante, 2),
                status="good",
                message="Datorii cu scadență depășită"
            )
        )

        logger.info(
            f"Cash flow indicators for company {company_id}, luna={luna}, an={an}: "
            f"flux_net_lunar={flux_net_lunar.value} ({flux_net_lunar.status}), "
            f"cash_flow_ytd={cash_flow_ytd.value} ({cash_flow_ytd.status}), "
            f"flux_net_yoy_pct={flux_net_yoy_pct.value}% ({flux_net_yoy_pct.status}), "
            f"acoperire_cf={acoperire_cash_flow.value} ({acoperire_cash_flow.status})"
        )

        return result

    @staticmethod
    @cached(cache_type='fin_dynamics', key_params=['company_id', 'luna', 'an', 'server_id'])
    async def calculate_dynamics_indicators(
        company_id: int,
        luna: int,
        an: int,
        server_id: Optional[str] = None
    ) -> DynamicsIndicators:
        """
        Calculează indicatorii de dinamică pentru evaluarea evoluției afacerii.

        Compară vânzările și achizițiile cu anul anterior (YoY - Year-over-Year)
        pentru a determina dacă afacerea crește sau scade.

        SURSE DE DATE (toate FĂRĂ TVA):
        - Vânzări: Cifra de Afaceri din VBAL (Clasa 7 - conturile 70x)
        - Achiziții: Registru Jurnal ACT (stocuri 3x=4x + cheltuieli directe 6x=4x)

        Anterior, indicatorii foloseau vbalanta_parteneri care include TVA în 4111
        (Clienți DEBIT), ceea ce ducea la cifre ~20% mai mari decât realitatea.

        Indicatori calculați:
        - crestere_vanzari_yoy: Creșterea procentuală a Cifrei de Afaceri față de anul anterior
          Formula: (CA_curent - CA_anterior) / CA_anterior * 100
          Good: > 5%, Warning: 0-5%, Danger: < 0%

        - crestere_achizitii_yoy: Creșterea procentuală a achizițiilor totale față de anul anterior
          Formula: (achizitii_curent - achizitii_anterior) / achizitii_anterior * 100
          Sursa: ACT (include stocuri + cheltuieli directe, fără TVA)
          Informativ - creșterea achizițiilor poate indica expansiune

        - marja_implicita: Marja implicită din diferența CA - achiziții totale
          Formula: (CA - achizitii) / CA * 100
          Good: > 20%, Warning: 10-20%, Danger: < 10%

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12)
            an: Anul contabil

        Returns:
            DynamicsIndicators cu cei trei indicatori de dinamică
        """
        # Obținem agregatele pentru anul curent și anul anterior
        # Cifra de Afaceri (70x) din VBAL - FĂRĂ TVA
        aggregates_curent = await FinancialIndicatorsService.get_balance_sheet_aggregates(
            company_id, luna, an, server_id
        )
        aggregates_anterior = await FinancialIndicatorsService.get_balance_sheet_aggregates(
            company_id, luna, an - 1, server_id
        )

        # Ensure aggregates is a BalanceSheetAggregates model (cache may return dict)
        if isinstance(aggregates_curent, dict):
            aggregates_curent = BalanceSheetAggregates(**aggregates_curent)
        if isinstance(aggregates_anterior, dict):
            aggregates_anterior = BalanceSheetAggregates(**aggregates_anterior)

        # Cifra de Afaceri YTD (Clasa 7 - 70x, FĂRĂ TVA)
        # Aceasta este sursa corectă pentru vânzări
        total_vanzari_curent = float(aggregates_curent.cifra_afaceri)
        total_vanzari_anterior = float(aggregates_anterior.cifra_afaceri)

        # Achiziții TOTALE YTD din ACT (stocuri + cheltuieli directe, FĂRĂ TVA)
        # Include: 3x=4x (stocuri) + 6x=4x (servicii, consumabile)
        # Exclude: discount/rabat (40x=667/609)
        achizitii_curent = await FinancialIndicatorsService.get_achizitii_ytd(
            company_id, luna, an, server_id
        )
        achizitii_anterior = await FinancialIndicatorsService.get_achizitii_ytd(
            company_id, luna, an - 1, server_id
        )
        total_achizitii_curent = float(achizitii_curent)
        total_achizitii_anterior = float(achizitii_anterior)

        # 1. Creștere vânzări YoY (Cifra de Afaceri)
        # Formula: (CA_curent - CA_anterior) / CA_anterior * 100
        if total_vanzari_anterior > 0:
            crestere_vanzari_val = (
                (total_vanzari_curent - total_vanzari_anterior) /
                total_vanzari_anterior * 100
            )
            # Status: good > 5%, warning 0-5%, danger < 0%
            crestere_vanzari_status = FinancialIndicatorsService._calculate_indicator_status(
                crestere_vanzari_val,
                good_threshold=5.0,
                warning_threshold=0.0
            )
            crestere_vanzari_message = (
                "Creștere semnificativă a vânzărilor"
                if crestere_vanzari_val > 5
                else "Vânzări stabile"
                if crestere_vanzari_val >= 0
                else "Vânzări în scădere"
            )
            crestere_vanzari_yoy = IndicatorResult(
                value=round(crestere_vanzari_val, 1),
                status=crestere_vanzari_status,
                threshold_min=5.0,
                threshold_max=None,
                message=crestere_vanzari_message
            )
        elif total_vanzari_curent > 0:
            # Anul anterior nu avea vânzări, dar anul curent da
            crestere_vanzari_yoy = IndicatorResult(
                value=100.0,
                status="good",
                threshold_min=5.0,
                threshold_max=None,
                message="Vânzări noi - nu existau în anul anterior"
            )
        else:
            # Fără vânzări în niciun an
            crestere_vanzari_yoy = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=5.0,
                threshold_max=None,
                message="Fără date de vânzări pentru comparație"
            )

        # 2. Creștere achiziții YoY
        # Formula: (achizitii_curent - achizitii_anterior) / achizitii_anterior * 100
        if total_achizitii_anterior > 0:
            crestere_achizitii_val = (
                (total_achizitii_curent - total_achizitii_anterior) /
                total_achizitii_anterior * 100
            )
            # Pentru achiziții, creșterea poate fi neutră (expansiune) sau negativă (reducere)
            # Nu există un "danger" clar - e informativ
            crestere_achizitii_message = (
                "Achiziții în creștere - posibilă expansiune"
                if crestere_achizitii_val > 5
                else "Achiziții stabile"
                if crestere_achizitii_val >= -5
                else "Achiziții în scădere"
            )
            crestere_achizitii_yoy = IndicatorResult(
                value=round(crestere_achizitii_val, 1),
                status="good",  # Informativ - nu are praguri stricte
                threshold_min=None,
                threshold_max=None,
                message=crestere_achizitii_message
            )
        elif total_achizitii_curent > 0:
            crestere_achizitii_yoy = IndicatorResult(
                value=100.0,
                status="good",
                threshold_min=None,
                threshold_max=None,
                message="Achiziții noi - nu existau în anul anterior"
            )
        else:
            crestere_achizitii_yoy = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=None,
                threshold_max=None,
                message="Fără date de achiziții pentru comparație"
            )

        # 3. Marja implicită
        # Formula: (CA - achizitii_stocuri) / CA * 100
        # Arată ce procent din Cifra de Afaceri rămâne după achiziții de stocuri
        if total_vanzari_curent > 0:
            marja_val = (
                (total_vanzari_curent - total_achizitii_curent) /
                total_vanzari_curent * 100
            )
            # Status: good > 20%, warning 10-20%, danger < 10%
            marja_status = FinancialIndicatorsService._calculate_indicator_status(
                marja_val,
                good_threshold=20.0,
                warning_threshold=10.0
            )
            marja_message = (
                "Marjă implicită sănătoasă"
                if marja_val > 20
                else "Marjă implicită moderată"
                if marja_val >= 10
                else "Marjă implicită redusă - verificați costurile"
            )
            marja_implicita = IndicatorResult(
                value=round(marja_val, 1),
                status=marja_status,
                threshold_min=20.0,
                threshold_max=None,
                message=marja_message
            )
        else:
            marja_implicita = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=20.0,
                threshold_max=None,
                message="Fără vânzări - nu se poate calcula marja"
            )

        result = DynamicsIndicators(
            crestere_vanzari_yoy=crestere_vanzari_yoy,
            crestere_achizitii_yoy=crestere_achizitii_yoy,
            marja_implicita=marja_implicita,
            # Sub-indicatori pentru verificare manuală
            # IMPORTANT: Acestea sunt acum FĂRĂ TVA (Cifra de Afaceri din Clasa 7)
            vanzari_an_curent=IndicatorResult(
                value=round(total_vanzari_curent, 2),
                status="good",
                message="Cifra de Afaceri YTD an curent (fără TVA)"
            ),
            vanzari_an_precedent=IndicatorResult(
                value=round(total_vanzari_anterior, 2),
                status="good",
                message="Cifra de Afaceri YTD an precedent (fără TVA)"
            ),
            achizitii_an_curent=IndicatorResult(
                value=round(total_achizitii_curent, 2),
                status="good",
                message="Achiziții totale YTD an curent (stocuri + cheltuieli directe, fără TVA)"
            ),
            achizitii_an_precedent=IndicatorResult(
                value=round(total_achizitii_anterior, 2),
                status="good",
                message="Achiziții totale YTD an precedent (stocuri + cheltuieli directe, fără TVA)"
            )
        )

        logger.info(
            f"Dynamics indicators for company {company_id}, luna={luna}, an={an}: "
            f"crestere_vanzari_yoy={crestere_vanzari_yoy.value}% ({crestere_vanzari_yoy.status}), "
            f"crestere_achizitii_yoy={crestere_achizitii_yoy.value}% ({crestere_achizitii_yoy.status}), "
            f"marja_implicita={marja_implicita.value}% ({marja_implicita.status})"
        )

        return result

    @staticmethod
    @cached(cache_type='fin_altman', key_params=['company_id', 'luna', 'an', 'server_id'])
    async def calculate_altman_zscore(
        company_id: int,
        luna: int,
        an: int,
        server_id: Optional[str] = None
    ) -> AltmanZScore:
        """
        Calculează Altman Z-Score pentru evaluarea riscului de faliment.

        Folosim formula modificată pentru companii private (Z'-Score):
        Z' = 6.56*X1 + 3.26*X2 + 6.72*X3 + 1.05*X4

        Aceasta este versiunea pentru companii care nu sunt listate la bursă,
        unde se folosește valoarea contabilă a capitalurilor proprii (Book Value)
        în loc de valoarea de piață a acțiunilor.

        Componente:
        - X1 = Working Capital / Total Assets (lichiditate pe termen scurt)
        - X2 = Retained Earnings / Total Assets (profitabilitate cumulată)
        - X3 = EBIT / Total Assets (eficiență operațională)
        - X4 = Book Value of Equity / Total Liabilities (solvabilitate)

        Zone de risc:
        - Safe (Z > 2.60): Risc minim de faliment - situație financiară solidă
        - Grey (1.10 <= Z <= 2.60): Zona de incertitudine - necesită monitorizare
        - Distress (Z < 1.10): Risc ridicat de faliment - situație critică

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12)
            an: Anul contabil

        Returns:
            AltmanZScore cu scorul calculat și componentele individuale x1, x2, x3, x4
        """
        # Obținem agregatele din balanță
        aggregates = await FinancialIndicatorsService.get_balance_sheet_aggregates(
            company_id, luna, an, server_id
        )
        # Ensure aggregates is a BalanceSheetAggregates model (cache may return dict)
        if isinstance(aggregates, dict):
            aggregates = BalanceSheetAggregates(**aggregates)

        # Calculăm componentele necesare
        # Working Capital = active_curente - datorii_curente
        working_capital = float(aggregates.working_capital)

        # Total Assets = active_imobilizate + active_curente
        total_assets = float(aggregates.total_active)

        # Rezultat reportat (cont 117 + 121) - deja agregat în `rezultat`
        rezultat_reportat = float(aggregates.rezultat)

        # EBIT = venituri - cheltuieli_operationale
        ebit = float(aggregates.ebit)

        # Capital propriu (inclusiv rezultat) pentru X4
        capital_propriu = float(aggregates.capitaluri_proprii)

        # Total datorii (curente + termen lung)
        total_datorii = float(aggregates.total_datorii)
        datorii_curente = float(aggregates.datorii_curente)
        datorii_termen_lung = float(aggregates.datorii_termen_lung)

        # Verificăm dacă avem date suficiente pentru calcul
        if total_assets == 0:
            # Nu putem calcula Z-Score fără active
            return AltmanZScore(
                zscore=IndicatorResult(
                    value=None,
                    status="warning",
                    threshold_min=2.60,
                    threshold_max=None,
                    message="Nu se poate calcula - total active este zero"
                ),
                x1=IndicatorResult(value=None, status="warning"),
                x2=IndicatorResult(value=None, status="warning"),
                x3=IndicatorResult(value=None, status="warning"),
                x4=IndicatorResult(value=None, status="warning"),
                capital_de_lucru=IndicatorResult(
                    value=round(working_capital, 2),
                    status="warning",
                    message="Active Curente - Datorii Curente"
                ),
                active_totale=IndicatorResult(
                    value=0,
                    status="warning",
                    message="Nu există active în balanță"
                ),
                datorii_totale=IndicatorResult(
                    value=round(total_datorii, 2),
                    status="warning",
                    message="Datorii Curente + Datorii Termen Lung"
                )
            )

        # Calculăm componentele X1-X4

        # X1 = Working Capital / Total Assets
        # Măsoară lichiditatea - cât de mult din active este finanțat din surse pe termen scurt
        x1_val = working_capital / total_assets
        x1_status = "good" if x1_val > 0 else "danger"
        x1 = IndicatorResult(
            value=round(x1_val, 4),
            status=x1_status,
            threshold_min=0,
            threshold_max=None,
            message="Lichiditate pe termen scurt" if x1_val > 0 else "Working capital negativ"
        )

        # X2 = Retained Earnings / Total Assets
        # Măsoară profitabilitatea cumulată - câștigurile reinvestite în companie
        x2_val = rezultat_reportat / total_assets
        x2_status = "good" if x2_val > 0 else ("warning" if x2_val == 0 else "danger")
        x2 = IndicatorResult(
            value=round(x2_val, 4),
            status=x2_status,
            threshold_min=0,
            threshold_max=None,
            message="Profitabilitate cumulată" if x2_val >= 0 else "Pierderi cumulate"
        )

        # X3 = EBIT / Total Assets
        # Măsoară eficiența operațională - randamentul activelor
        x3_val = ebit / total_assets
        x3_status = "good" if x3_val > 0 else ("warning" if x3_val == 0 else "danger")
        x3 = IndicatorResult(
            value=round(x3_val, 4),
            status=x3_status,
            threshold_min=0,
            threshold_max=None,
            message="Eficiență operațională" if x3_val >= 0 else "Pierdere operațională"
        )

        # X4 = Book Value of Equity / Total Liabilities
        # Măsoară solvabilitatea - acoperirea datoriilor cu capital propriu
        if total_datorii > 0:
            x4_val = capital_propriu / total_datorii
            x4_status = FinancialIndicatorsService._calculate_indicator_status(
                x4_val,
                good_threshold=1.0,
                warning_threshold=0.5
            )
            x4 = IndicatorResult(
                value=round(x4_val, 4),
                status=x4_status,
                threshold_min=1.0,
                threshold_max=None,
                message="Solvabilitate bună" if x4_val >= 1 else "Îndatorare ridicată"
            )
        else:
            # Fără datorii - situație excelentă pentru solvabilitate
            x4_val = None  # Infinit teoretic, dar nu putem reprezenta
            x4 = IndicatorResult(
                value=None,
                status="good",
                threshold_min=1.0,
                threshold_max=None,
                message="Fără datorii - solvabilitate maximă"
            )

        # Calculăm Z-Score folosind formula pentru companii private
        # Z' = 6.56*X1 + 3.26*X2 + 6.72*X3 + 1.05*X4
        if x4_val is not None:
            zscore_val = (
                6.56 * x1_val +
                3.26 * x2_val +
                6.72 * x3_val +
                1.05 * x4_val
            )
        else:
            # Dacă X4 este infinit (fără datorii), calculăm Z-Score fără componenta X4
            # În practică, firmele fără datorii au un Z-Score foarte bun
            # Folosim o valoare foarte mare pentru X4 (ex: 10) ca proxy
            zscore_val = (
                6.56 * x1_val +
                3.26 * x2_val +
                6.72 * x3_val +
                1.05 * 10.0  # Proxy pentru solvabilitate maximă
            )

        # Determinăm zona de risc
        if zscore_val > 2.60:
            zscore_status = "safe"
            zscore_message = "Zona sigură - risc minim de faliment"
        elif zscore_val >= 1.10:
            zscore_status = "grey"
            zscore_message = "Zona gri - necesită monitorizare atentă"
        else:
            zscore_status = "distress"
            zscore_message = "Zona de risc - risc ridicat de faliment"

        zscore = IndicatorResult(
            value=round(zscore_val, 2),
            status=zscore_status,
            threshold_min=2.60,
            threshold_max=None,
            message=zscore_message
        )

        # Indicatori de bază pentru verificare manuală în balanță
        capital_de_lucru = IndicatorResult(
            value=round(working_capital, 2),
            status="good" if working_capital > 0 else "danger",
            threshold_min=0,
            threshold_max=None,
            message="Active Curente - Datorii Curente"
        )

        active_totale_ind = IndicatorResult(
            value=round(total_assets, 2),
            status="good",
            threshold_min=None,
            threshold_max=None,
            message="Active Imobilizate + Active Curente"
        )

        datorii_totale_ind = IndicatorResult(
            value=round(total_datorii, 2),
            status="good",
            threshold_min=None,
            threshold_max=None,
            message="Datorii Curente + Datorii Termen Lung"
        )

        result = AltmanZScore(
            zscore=zscore,
            x1=x1,
            x2=x2,
            x3=x3,
            x4=x4,
            capital_de_lucru=capital_de_lucru,
            active_totale=active_totale_ind,
            datorii_totale=datorii_totale_ind
        )

        logger.info(
            f"Altman Z-Score for company {company_id}, luna={luna}, an={an}: "
            f"zscore={zscore.value} ({zscore.status}), "
            f"X1={x1.value}, X2={x2.value}, X3={x3.value}, X4={x4.value}"
        )

        return result

    @staticmethod
    @cached(cache_type='fin_profitability', key_params=['company_id', 'luna', 'an', 'server_id'])
    async def calculate_profitability_indicators(
        company_id: int,
        luna: int,
        an: int,
        server_id: Optional[str] = None
    ) -> ProfitabilityIndicators:
        """
        Calculează indicatorii de profitabilitate pentru evaluarea randamentului afacerii.

        Indicatori calculați:
        - cifra_afaceri: Total venituri operaționale (Clasa 7)
        - cheltuieli_totale: Total cheltuieli operaționale (Clasa 6)
        - profit_brut: EBIT = venituri - cheltuieli
        - marja_profit_brut: profit / venituri * 100
        - roa: Return on Assets = profit / total_active * 100
        - roe: Return on Equity = profit / capitaluri_proprii * 100

        Praguri de referință:
        - Marja profit: good > 10%, warning 5-10%, danger < 5%
        - ROA: good > 5%, warning 2-5%, danger < 2%
        - ROE: good > 10%, warning 5-10%, danger < 5%

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12)
            an: Anul contabil

        Returns:
            ProfitabilityIndicators cu cei șase indicatori de profitabilitate
        """
        # Obținem agregatele din balanță (include venituri, cheltuieli, active, capital)
        aggregates = await FinancialIndicatorsService.get_balance_sheet_aggregates(
            company_id, luna, an, server_id
        )
        # Ensure aggregates is a BalanceSheetAggregates model (cache may return dict)
        if isinstance(aggregates, dict):
            aggregates = BalanceSheetAggregates(**aggregates)

        # Extragem valorile necesare
        venituri = float(aggregates.venituri)
        cheltuieli_oper = float(aggregates.cheltuieli_operationale)
        cheltuieli_fin = float(aggregates.cheltuieli_financiare)
        cheltuieli_total = cheltuieli_oper + cheltuieli_fin
        profit_brut_val = float(aggregates.ebit)  # EBIT = venituri - cheltuieli operaționale
        total_active = float(aggregates.total_active)
        capitaluri_proprii_val = float(aggregates.capitaluri_proprii)

        # Detect if balance sheet has data but income/expense accounts are 0
        # This typically means the accounting period is not closed in Oracle
        has_balance_data = total_active > 0 or float(aggregates.datorii_curente) > 0
        no_income_data = venituri == 0 and cheltuieli_oper == 0
        period_not_closed = has_balance_data and no_income_data

        # 1. Cifra de afaceri (venituri totale) - informativ
        if period_not_closed:
            cifra_afaceri_status = "warning"
            cifra_afaceri_message = "Date indisponibile - perioada contabilă neînchisă?"
        else:
            cifra_afaceri_status = "good"
            cifra_afaceri_message = "Total venituri din activitatea operațională"

        cifra_afaceri = IndicatorResult(
            value=round(venituri, 2),
            status=cifra_afaceri_status,
            threshold_min=None,
            threshold_max=None,
            message=cifra_afaceri_message
        )

        # 2. Cheltuieli operaționale (fără dobânzi 66x) - pentru verificare
        cheltuieli_operationale = IndicatorResult(
            value=round(cheltuieli_oper, 2),
            status="good",  # Informativ - nu are praguri
            threshold_min=None,
            threshold_max=None,
            message="Clasa 60x-65x + 68x (fără dobânzi)"
        )

        # 3. Cheltuieli financiare (66x) - pentru verificare
        cheltuieli_financiare = IndicatorResult(
            value=round(cheltuieli_fin, 2),
            status="good",  # Informativ - nu are praguri
            threshold_min=None,
            threshold_max=None,
            message="Clasa 66x (dobânzi, diferențe curs)"
        )

        # 4. Cheltuieli totale (operaționale + financiare)
        cheltuieli_totale = IndicatorResult(
            value=round(cheltuieli_total, 2),
            status="good",  # Informativ - nu are praguri
            threshold_min=None,
            threshold_max=None,
            message="Operaționale + Financiare"
        )

        # 3. Profit brut (EBIT)
        if period_not_closed:
            profit_status = "warning"
            profit_message = "Date indisponibile - perioada contabilă neînchisă?"
        elif profit_brut_val > 0:
            profit_status = "good"
            profit_message = "Profit operațional pozitiv"
        else:
            profit_status = "danger"
            profit_message = "Pierdere operațională - costuri depășesc veniturile"

        profit_brut = IndicatorResult(
            value=round(profit_brut_val, 2),
            status=profit_status,
            threshold_min=0,
            threshold_max=None,
            message=profit_message
        )

        # 4. Marja de profit = profit / venituri * 100
        if venituri > 0:
            marja_val = (profit_brut_val / venituri) * 100
            marja_status = FinancialIndicatorsService._calculate_indicator_status(
                marja_val,
                good_threshold=10.0,
                warning_threshold=5.0
            )
            marja_message = (
                "Marjă de profit sănătoasă"
                if marja_val > 10
                else "Marjă de profit moderată"
                if marja_val >= 5
                else "Marjă de profit scăzută - verificați costurile"
            )
            marja_profit_brut = IndicatorResult(
                value=round(marja_val, 1),
                status=marja_status,
                threshold_min=10.0,
                threshold_max=None,
                message=marja_message
            )
        else:
            marja_profit_brut = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=10.0,
                threshold_max=None,
                message="Fără venituri - nu se poate calcula marja"
            )

        # 5. ROA (Return on Assets) = profit / total_active * 100
        if total_active > 0:
            roa_val = (profit_brut_val / total_active) * 100
            roa_status = FinancialIndicatorsService._calculate_indicator_status(
                roa_val,
                good_threshold=5.0,
                warning_threshold=2.0
            )
            roa_message = (
                "Randament bun al activelor"
                if roa_val > 5
                else "Randament moderat al activelor"
                if roa_val >= 2
                else "Randament scăzut al activelor"
            )
            roa = IndicatorResult(
                value=round(roa_val, 2),
                status=roa_status,
                threshold_min=5.0,
                threshold_max=None,
                message=roa_message
            )
        else:
            roa = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=5.0,
                threshold_max=None,
                message="Fără active - nu se poate calcula ROA"
            )

        # Indicatori de bază pentru verificare manuală în balanță
        active_totale = IndicatorResult(
            value=round(total_active, 2),
            status="good",
            threshold_min=None,
            threshold_max=None,
            message="Active Imobilizate + Active Curente (bază calcul ROA)"
        )

        capitaluri_proprii = IndicatorResult(
            value=round(capitaluri_proprii_val, 2),
            status="good" if capitaluri_proprii_val > 0 else "danger",
            threshold_min=None,
            threshold_max=None,
            message="Capital Social + Rezultat (bază calcul ROE)"
        )

        # ROE (Return on Equity) = profit / capitaluri_proprii * 100
        if capitaluri_proprii_val > 0:
            roe_val = (profit_brut_val / capitaluri_proprii_val) * 100
            roe_status = FinancialIndicatorsService._calculate_indicator_status(
                roe_val,
                good_threshold=10.0,
                warning_threshold=5.0
            )
            roe_message = (
                "Randament atractiv pentru acționari"
                if roe_val > 10
                else "Randament moderat pentru acționari"
                if roe_val >= 5
                else "Randament scăzut pentru acționari"
            )
            roe = IndicatorResult(
                value=round(roe_val, 2),
                status=roe_status,
                threshold_min=10.0,
                threshold_max=None,
                message=roe_message
            )
        elif capitaluri_proprii_val <= 0 and profit_brut_val > 0:
            # Capital negativ dar profit pozitiv - situație neobișnuită
            roe = IndicatorResult(
                value=None,
                status="danger",
                threshold_min=10.0,
                threshold_max=None,
                message="Capital propriu negativ sau zero - situație de risc"
            )
        else:
            roe = IndicatorResult(
                value=None,
                status="warning",
                threshold_min=10.0,
                threshold_max=None,
                message="Nu se poate calcula ROE"
            )

        result = ProfitabilityIndicators(
            cifra_afaceri=cifra_afaceri,
            cheltuieli_operationale=cheltuieli_operationale,
            cheltuieli_financiare=cheltuieli_financiare,
            cheltuieli_totale=cheltuieli_totale,
            profit_brut=profit_brut,
            # Sub-indicator pentru verificare calcul EBIT
            venituri=IndicatorResult(
                value=round(venituri, 2),
                status="good",
                message="Total venituri (Clasa 7) - verificare EBIT"
            ),
            marja_profit_brut=marja_profit_brut,
            active_totale=active_totale,
            capitaluri_proprii=capitaluri_proprii,
            roa=roa,
            roe=roe
        )

        logger.info(
            f"Profitability indicators for company {company_id}, luna={luna}, an={an}: "
            f"cifra_afaceri={cifra_afaceri.value}, "
            f"profit_brut={profit_brut.value} ({profit_brut.status}), "
            f"marja={marja_profit_brut.value}% ({marja_profit_brut.status}), "
            f"roa={roa.value}% ({roa.status}), "
            f"roe={roe.value}% ({roe.status})"
        )

        return result

    @staticmethod
    async def calculate_solvability_indicators(
        company_id: int,
        luna: int,
        an: int,
        server_id: Optional[str] = None
    ) -> SolvabilityIndicators:
        """
        Calculează indicatorii de solvabilitate pentru evaluarea capacității
        firmei de a-și acoperi datoriile pe termen lung.

        Indicatori calculați:
        - Activ Net Contabil (ANC) = Total Active - Total Datorii
        - Rata ANC/Capital Social = (ANC / Capital Social) × 100

        Praguri de referință:
        - ANC: Good: > 0, Danger: <= 0
        - Rata ANC/Capital: Good: >= 100%, Warning: 50-100%, Danger: < 50%

        Implicații legale (din 1 ianuarie 2026):
        Sub 50% din capital social → restricții dividende, restituire împrumuturi,
        acordare împrumuturi noi.

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12)
            an: Anul contabil

        Returns:
            SolvabilityIndicators cu ANC și rata ANC/Capital Social
        """
        # Obținem agregatele din balanță
        aggregates = await FinancialIndicatorsService.get_balance_sheet_aggregates(
            company_id, luna, an, server_id
        )
        # Ensure aggregates is a BalanceSheetAggregates model (cache may return dict)
        if isinstance(aggregates, dict):
            aggregates = BalanceSheetAggregates(**aggregates)

        # Extragem valorile necesare
        total_active = float(aggregates.total_active)
        total_datorii = float(aggregates.total_datorii)
        # Folosim capital_social_strict (doar contul 101) conform definiției legale stricte
        capital_social = float(aggregates.capital_social_strict)  # Capital Social = doar contul 101

        # 1. Calculăm Activul Net Contabil (ANC)
        anc_val = total_active - total_datorii

        # Status pentru ANC: pozitiv = good, negativ sau zero = danger
        if anc_val > 0:
            anc_status = "good"
            anc_message = "Activ net pozitiv - firma solvabilă"
        else:
            anc_status = "danger"
            anc_message = "Activ net negativ sau zero - risc de insolvență"

        activ_net_contabil = IndicatorResult(
            value=round(anc_val, 2),
            status=anc_status,
            threshold_min=0,
            threshold_max=None,
            message=anc_message
        )

        # 2. Calculăm Rata ANC / Capital Social
        if capital_social > 0:
            rata_val = (anc_val / capital_social) * 100

            # Praguri conform legislației din 2026
            if rata_val >= 100:
                rata_status = "good"
                rata_message = "ANC peste capitalul social - situație sănătoasă"
            elif rata_val >= 50:
                rata_status = "warning"
                rata_message = "ANC între 50-100% din capital - atenție la evoluție"
            else:
                rata_status = "danger"
                rata_message = "ANC sub 50% din capital - restricții legale aplicabile"

            rata_anc_capital = IndicatorResult(
                value=round(rata_val, 2),
                status=rata_status,
                threshold_min=100.0,
                threshold_max=None,
                message=rata_message
            )
        else:
            # Capital social zero sau negativ - situație critică
            rata_anc_capital = IndicatorResult(
                value=None,
                status="danger",
                threshold_min=100.0,
                threshold_max=None,
                message="Capital social zero sau negativ - situație critică"
            )

        # Indicatori de bază pentru verificare
        total_active_indicator = IndicatorResult(
            value=round(total_active, 2),
            status="good",
            threshold_min=None,
            threshold_max=None,
            message="Active Imobilizate + Active Curente"
        )

        total_datorii_indicator = IndicatorResult(
            value=round(total_datorii, 2),
            status="good" if total_datorii < total_active else "warning",
            threshold_min=None,
            threshold_max=None,
            message="Datorii Curente + Datorii Termen Lung"
        )

        capital_social_indicator = IndicatorResult(
            value=round(capital_social, 2),
            status="good" if capital_social > 0 else "danger",
            threshold_min=None,
            threshold_max=None,
            message="Capital social subscris și vărsat"
        )

        result = SolvabilityIndicators(
            activ_net_contabil=activ_net_contabil,
            rata_anc_capital=rata_anc_capital,
            total_active=total_active_indicator,
            total_datorii=total_datorii_indicator,
            capital_social=capital_social_indicator
        )

        logger.info(
            f"Solvability indicators for company {company_id}, luna={luna}, an={an}: "
            f"ANC={activ_net_contabil.value} ({activ_net_contabil.status}), "
            f"Rata ANC/CS={rata_anc_capital.value}% ({rata_anc_capital.status})"
        )

        return result

    @staticmethod
    def _generate_month_labels(luna: int, an: int, months: int = 12) -> List[str]:
        """
        Generează etichetele lunilor în format 'MMM YY' pentru sparkline.

        Generează etichete pentru ultimele `months` luni, terminând cu luna/an specificată.
        Folosim abrevieri în engleză pentru consistență internațională.

        Args:
            luna: Luna finală (1-12)
            an: Anul final
            months: Numărul de luni de generat (default 12)

        Returns:
            Lista de etichete în format 'MMM YY' (ex: ['Feb 24', 'Mar 24', ...])
        """
        MONTH_ABBR = [
            'Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun',
            'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
        ]

        labels = []
        current_luna = luna
        current_an = an

        # Generăm etichetele de la luna curentă înapoi
        for _ in range(months):
            year_short = str(current_an)[-2:]  # Ultimele 2 cifre ale anului
            label = f"{MONTH_ABBR[current_luna - 1]} {year_short}"
            labels.insert(0, label)  # Inserăm la început pentru ordine cronologică

            # Mergem la luna anterioară
            current_luna -= 1
            if current_luna < 1:
                current_luna = 12
                current_an -= 1

        return labels

    @staticmethod
    def _get_historical_periods(luna: int, an: int, months: int = 12) -> List[tuple]:
        """
        Generează lista de perioade (luna, an) pentru ultimele `months` luni.

        Args:
            luna: Luna finală (1-12)
            an: Anul final
            months: Numărul de luni (default 12)

        Returns:
            Lista de tuple (luna, an) în ordine cronologică
        """
        periods = []
        current_luna = luna
        current_an = an

        for _ in range(months):
            periods.insert(0, (current_luna, current_an))

            current_luna -= 1
            if current_luna < 1:
                current_luna = 12
                current_an -= 1

        return periods

    @staticmethod
    @cached(cache_type='financial_indicators_historical', ttl=3600, key_params=['company_id', 'months', 'luna', 'an', 'server_id'])
    async def get_historical_indicators(
        company_id: int,
        months: int = 12,
        luna: Optional[int] = None,
        an: Optional[int] = None,
        server_id: Optional[str] = None
    ) -> Dict[str, Any]:
        """
        Calculează indicatorii financiari pentru ultimele `months` luni
        și returnează datele pentru sparklines.

        Această metodă este optimizată pentru performanță cu cache separat
        (TTL 1 oră) deoarece datele istorice se schimbă rar.

        Args:
            company_id: ID-ul firmei
            months: Numărul de luni pentru istoric (default 12)
            luna: Luna de referință (dacă None, folosește luna curentă)
            an: Anul de referință (dacă None, folosește anul curent)

        Returns:
            Dict cu:
            - sparkline_labels: Array cu etichetele lunilor
            - lichiditate: Dict cu sparkline_data pentru fiecare indicator
            - eficienta: Dict cu sparkline_data pentru fiecare indicator
            - risc: Dict cu sparkline_data pentru fiecare indicator
            - cash_flow: Dict cu sparkline_data pentru fiecare indicator
            - dinamica: Dict cu sparkline_data pentru fiecare indicator
            - altman_zscore: Dict cu sparkline_data pentru fiecare indicator
        """
        from datetime import datetime

        # Dacă luna/an nu sunt specificate, folosim data curentă
        resolved_luna: int
        resolved_an: int

        if luna is None or an is None:
            try:
                from .dashboard_service import DashboardService
                current_period = await DashboardService.get_current_period(company_id)
                resolved_luna = luna if luna is not None else current_period.get('luna', datetime.now().month)
                resolved_an = an if an is not None else current_period.get('an', datetime.now().year)
            except Exception as e:
                logger.warning(f"Could not get current period: {e}, using defaults")
                resolved_luna = luna if luna is not None else datetime.now().month
                resolved_an = an if an is not None else datetime.now().year
        else:
            resolved_luna = luna
            resolved_an = an

        # Generăm perioadele și etichetele
        periods = FinancialIndicatorsService._get_historical_periods(resolved_luna, resolved_an, months)
        labels = FinancialIndicatorsService._generate_month_labels(resolved_luna, resolved_an, months)

        # Inițializăm structurile pentru sparkline data
        historical_data = {
            'sparkline_labels': labels,
            'lichiditate': {
                'lichiditate_curenta': [],
                'lichiditate_imediata': [],
                'lichiditate_vedere': []
            },
            'eficienta': {
                'dso': [],
                'dpo': [],
                'cash_conversion_cycle': [],
                'rata_incasare': [],
                'rata_plata': []
            },
            'risc': {
                'creante_restante_pct': [],
                'creante_90plus_pct': [],
                'datorii_restante_pct': [],
                'raport_datorii_trezorerie': []
            },
            'cash_flow': {
                'flux_net_lunar': [],
                'cash_flow_ytd': [],
                'flux_net_yoy_pct': [],
                'acoperire_cash_flow': []
            },
            'dinamica': {
                'crestere_vanzari_yoy': [],
                'crestere_achizitii_yoy': [],
                'marja_implicita': []
            },
            'altman_zscore': {
                'zscore': [],
                'x1': [],
                'x2': [],
                'x3': [],
                'x4': []
            },
            'profitabilitate': {
                'cifra_afaceri': [],
                'cheltuieli_totale': [],
                'profit_brut': [],
                'marja_profit_brut': [],
                'roa': [],
                'roe': []
            },
            'solvabilitate': {
                'activ_net_contabil': [],
                'rata_anc_capital': []
            }
        }

        # Calculăm indicatorii pentru fiecare perioadă
        all_categories = ['lichiditate', 'eficienta', 'risc', 'cash_flow', 'dinamica', 'altman_zscore', 'profitabilitate', 'solvabilitate']

        for period_luna, period_an in periods:
            # Track which categories were successfully processed in this period
            processed_categories = set()

            try:
                # Lichiditate
                lichiditate = await FinancialIndicatorsService.calculate_liquidity_indicators(
                    company_id, period_luna, period_an, server_id
                )
                # Ensure lichiditate is a model (cache may return dict)
                if isinstance(lichiditate, dict):
                    lichiditate = LiquidityIndicators(**lichiditate)
                historical_data['lichiditate']['lichiditate_curenta'].append(
                    lichiditate.lichiditate_curenta.value
                )
                historical_data['lichiditate']['lichiditate_imediata'].append(
                    lichiditate.lichiditate_imediata.value
                )
                historical_data['lichiditate']['lichiditate_vedere'].append(
                    lichiditate.lichiditate_vedere.value
                )
                processed_categories.add('lichiditate')

                # Eficiență
                eficienta = await FinancialIndicatorsService.calculate_efficiency_indicators(
                    company_id, period_luna, period_an, server_id
                )
                # Ensure eficienta is a model (cache may return dict)
                if isinstance(eficienta, dict):
                    eficienta = EfficiencyIndicators(**eficienta)
                historical_data['eficienta']['dso'].append(eficienta.dso.value)
                historical_data['eficienta']['dpo'].append(eficienta.dpo.value)
                historical_data['eficienta']['cash_conversion_cycle'].append(
                    eficienta.cash_conversion_cycle.value
                )
                historical_data['eficienta']['rata_incasare'].append(eficienta.rata_incasare.value)
                historical_data['eficienta']['rata_plata'].append(eficienta.rata_plata.value)
                processed_categories.add('eficienta')

                # Risc
                risc = await FinancialIndicatorsService.calculate_risk_indicators(
                    company_id, period_luna, period_an, server_id
                )
                # Ensure risc is a model (cache may return dict)
                if isinstance(risc, dict):
                    risc = RiskIndicators(**risc)
                historical_data['risc']['creante_restante_pct'].append(
                    risc.creante_restante_pct.value
                )
                historical_data['risc']['creante_90plus_pct'].append(risc.creante_90plus_pct.value)
                historical_data['risc']['datorii_restante_pct'].append(
                    risc.datorii_restante_pct.value
                )
                historical_data['risc']['raport_datorii_trezorerie'].append(
                    risc.raport_datorii_trezorerie.value
                )
                processed_categories.add('risc')

                # Cash Flow
                cash_flow = await FinancialIndicatorsService.calculate_cashflow_indicators(
                    company_id, period_luna, period_an, server_id
                )
                # Ensure cash_flow is a model (cache may return dict)
                if isinstance(cash_flow, dict):
                    cash_flow = CashFlowIndicators(**cash_flow)
                historical_data['cash_flow']['flux_net_lunar'].append(cash_flow.flux_net_lunar.value)
                historical_data['cash_flow']['cash_flow_ytd'].append(cash_flow.cash_flow_ytd.value)
                historical_data['cash_flow']['flux_net_yoy_pct'].append(
                    cash_flow.flux_net_yoy_pct.value
                )
                historical_data['cash_flow']['acoperire_cash_flow'].append(
                    cash_flow.acoperire_cash_flow.value
                )
                processed_categories.add('cash_flow')

                # Dinamica
                dinamica = await FinancialIndicatorsService.calculate_dynamics_indicators(
                    company_id, period_luna, period_an, server_id
                )
                # Ensure dinamica is a model (cache may return dict)
                if isinstance(dinamica, dict):
                    dinamica = DynamicsIndicators(**dinamica)
                historical_data['dinamica']['crestere_vanzari_yoy'].append(
                    dinamica.crestere_vanzari_yoy.value
                )
                historical_data['dinamica']['crestere_achizitii_yoy'].append(
                    dinamica.crestere_achizitii_yoy.value
                )
                historical_data['dinamica']['marja_implicita'].append(dinamica.marja_implicita.value)
                processed_categories.add('dinamica')

                # Altman Z-Score
                altman = await FinancialIndicatorsService.calculate_altman_zscore(
                    company_id, period_luna, period_an, server_id
                )
                # Ensure altman is a model (cache may return dict)
                if isinstance(altman, dict):
                    altman = AltmanZScore(**altman)
                historical_data['altman_zscore']['zscore'].append(altman.zscore.value)
                historical_data['altman_zscore']['x1'].append(altman.x1.value)
                historical_data['altman_zscore']['x2'].append(altman.x2.value)
                historical_data['altman_zscore']['x3'].append(altman.x3.value)
                historical_data['altman_zscore']['x4'].append(altman.x4.value)
                processed_categories.add('altman_zscore')

                # Profitabilitate
                profitabilitate = await FinancialIndicatorsService.calculate_profitability_indicators(
                    company_id, period_luna, period_an, server_id
                )
                # Ensure profitabilitate is a model (cache may return dict)
                if isinstance(profitabilitate, dict):
                    profitabilitate = ProfitabilityIndicators(**profitabilitate)
                historical_data['profitabilitate']['cifra_afaceri'].append(
                    profitabilitate.cifra_afaceri.value
                )
                historical_data['profitabilitate']['cheltuieli_totale'].append(
                    profitabilitate.cheltuieli_totale.value
                )
                historical_data['profitabilitate']['profit_brut'].append(
                    profitabilitate.profit_brut.value
                )
                historical_data['profitabilitate']['marja_profit_brut'].append(
                    profitabilitate.marja_profit_brut.value
                )
                historical_data['profitabilitate']['roa'].append(profitabilitate.roa.value)
                historical_data['profitabilitate']['roe'].append(profitabilitate.roe.value)
                processed_categories.add('profitabilitate')

                # Solvabilitate
                solvabilitate = await FinancialIndicatorsService.calculate_solvability_indicators(
                    company_id, period_luna, period_an, server_id
                )
                # Ensure solvabilitate is a model (cache may return dict)
                if isinstance(solvabilitate, dict):
                    solvabilitate = SolvabilityIndicators(**solvabilitate)
                historical_data['solvabilitate']['activ_net_contabil'].append(
                    solvabilitate.activ_net_contabil.value
                )
                historical_data['solvabilitate']['rata_anc_capital'].append(
                    solvabilitate.rata_anc_capital.value
                )
                processed_categories.add('solvabilitate')

            except Exception as e:
                logger.warning(
                    f"Error calculating indicators for company {company_id}, "
                    f"luna={period_luna}, an={period_an}: {e}"
                )

            # Add None ONLY for categories that were NOT successfully processed
            # This prevents duplicate entries when an exception occurs mid-way
            for category in all_categories:
                if category not in processed_categories:
                    for indicator in historical_data[category]:
                        historical_data[category][indicator].append(None)

        logger.info(
            f"Historical indicators for company {company_id}: "
            f"{months} months ending {resolved_luna}/{resolved_an}"
        )

        return historical_data

    @staticmethod
    @cached(cache_type='financial_indicators_sparklines', key_params=['company_id', 'luna', 'an', 'months', 'server_id'])
    async def get_indicators_with_sparklines(
        company_id: int,
        luna: int,
        an: int,
        months: int = 12,
        request: Optional[Request] = None,
        server_id: Optional[str] = None
    ) -> FinancialIndicatorsResponse:
        """
        Calculează toți indicatorii financiari și adaugă datele de sparkline
        pentru vizualizarea trendului pe ultimele luni (CACHED 30 min).

        Această metodă combină calculele curente ale indicatorilor cu
        datele istorice pentru sparklines.

        Args:
            company_id: ID-ul firmei
            luna: Luna contabilă (1-12)
            an: Anul contabil
            months: Numărul de luni pentru sparkline (default 12)
            request: Request object pentru cache metadata

        Returns:
            FinancialIndicatorsResponse cu sparkline_data integrat în fiecare indicator
        """
        import asyncio

        # Obținem datele istorice și indicatorii curenți în paralel
        historical_task = FinancialIndicatorsService.get_historical_indicators(
            company_id, months, luna, an, server_id
        )

        lichiditate_task = FinancialIndicatorsService.calculate_liquidity_indicators(
            company_id, luna, an, server_id
        )
        eficienta_task = FinancialIndicatorsService.calculate_efficiency_indicators(
            company_id, luna, an, server_id
        )
        risc_task = FinancialIndicatorsService.calculate_risk_indicators(
            company_id, luna, an, server_id
        )
        cash_flow_task = FinancialIndicatorsService.calculate_cashflow_indicators(
            company_id, luna, an, server_id
        )
        dinamica_task = FinancialIndicatorsService.calculate_dynamics_indicators(
            company_id, luna, an, server_id
        )
        altman_task = FinancialIndicatorsService.calculate_altman_zscore(
            company_id, luna, an, server_id
        )
        profitabilitate_task = FinancialIndicatorsService.calculate_profitability_indicators(
            company_id, luna, an, server_id
        )
        solvabilitate_task = FinancialIndicatorsService.calculate_solvability_indicators(
            company_id, luna, an, server_id
        )

        (
            historical_data,
            lichiditate,
            eficienta,
            risc,
            cash_flow,
            dinamica,
            altman_zscore,
            profitabilitate,
            solvabilitate
        ) = await asyncio.gather(
            historical_task,
            lichiditate_task,
            eficienta_task,
            risc_task,
            cash_flow_task,
            dinamica_task,
            altman_task,
            profitabilitate_task,
            solvabilitate_task
        )

        # Ensure all indicator results are models (cache may return dicts)
        if isinstance(lichiditate, dict):
            lichiditate = LiquidityIndicators(**lichiditate)
        if isinstance(eficienta, dict):
            eficienta = EfficiencyIndicators(**eficienta)
        if isinstance(risc, dict):
            risc = RiskIndicators(**risc)
        if isinstance(cash_flow, dict):
            cash_flow = CashFlowIndicators(**cash_flow)
        if isinstance(dinamica, dict):
            dinamica = DynamicsIndicators(**dinamica)
        if isinstance(altman_zscore, dict):
            altman_zscore = AltmanZScore(**altman_zscore)
        if isinstance(profitabilitate, dict):
            profitabilitate = ProfitabilityIndicators(**profitabilitate)
        if isinstance(solvabilitate, dict):
            solvabilitate = SolvabilityIndicators(**solvabilitate)

        # Extragem etichetele comune
        sparkline_labels = historical_data['sparkline_labels']

        # Actualizăm indicatorii de lichiditate cu sparkline data
        lichiditate.lichiditate_curenta.sparkline_data = historical_data['lichiditate']['lichiditate_curenta']
        lichiditate.lichiditate_curenta.sparkline_labels = sparkline_labels
        lichiditate.lichiditate_imediata.sparkline_data = historical_data['lichiditate']['lichiditate_imediata']
        lichiditate.lichiditate_imediata.sparkline_labels = sparkline_labels
        lichiditate.lichiditate_vedere.sparkline_data = historical_data['lichiditate']['lichiditate_vedere']
        lichiditate.lichiditate_vedere.sparkline_labels = sparkline_labels

        # Actualizăm indicatorii de eficiență cu sparkline data
        eficienta.dso.sparkline_data = historical_data['eficienta']['dso']
        eficienta.dso.sparkline_labels = sparkline_labels
        eficienta.dpo.sparkline_data = historical_data['eficienta']['dpo']
        eficienta.dpo.sparkline_labels = sparkline_labels
        eficienta.cash_conversion_cycle.sparkline_data = historical_data['eficienta']['cash_conversion_cycle']
        eficienta.cash_conversion_cycle.sparkline_labels = sparkline_labels
        eficienta.rata_incasare.sparkline_data = historical_data['eficienta']['rata_incasare']
        eficienta.rata_incasare.sparkline_labels = sparkline_labels
        eficienta.rata_plata.sparkline_data = historical_data['eficienta']['rata_plata']
        eficienta.rata_plata.sparkline_labels = sparkline_labels

        # Actualizăm indicatorii de risc cu sparkline data
        risc.creante_restante_pct.sparkline_data = historical_data['risc']['creante_restante_pct']
        risc.creante_restante_pct.sparkline_labels = sparkline_labels
        risc.creante_90plus_pct.sparkline_data = historical_data['risc']['creante_90plus_pct']
        risc.creante_90plus_pct.sparkline_labels = sparkline_labels
        risc.datorii_restante_pct.sparkline_data = historical_data['risc']['datorii_restante_pct']
        risc.datorii_restante_pct.sparkline_labels = sparkline_labels
        risc.raport_datorii_trezorerie.sparkline_data = historical_data['risc']['raport_datorii_trezorerie']
        risc.raport_datorii_trezorerie.sparkline_labels = sparkline_labels

        # Actualizăm indicatorii de cash flow cu sparkline data
        cash_flow.flux_net_lunar.sparkline_data = historical_data['cash_flow']['flux_net_lunar']
        cash_flow.flux_net_lunar.sparkline_labels = sparkline_labels
        cash_flow.cash_flow_ytd.sparkline_data = historical_data['cash_flow']['cash_flow_ytd']
        cash_flow.cash_flow_ytd.sparkline_labels = sparkline_labels
        cash_flow.flux_net_yoy_pct.sparkline_data = historical_data['cash_flow']['flux_net_yoy_pct']
        cash_flow.flux_net_yoy_pct.sparkline_labels = sparkline_labels
        cash_flow.acoperire_cash_flow.sparkline_data = historical_data['cash_flow']['acoperire_cash_flow']
        cash_flow.acoperire_cash_flow.sparkline_labels = sparkline_labels

        # Actualizăm indicatorii de dinamică cu sparkline data
        dinamica.crestere_vanzari_yoy.sparkline_data = historical_data['dinamica']['crestere_vanzari_yoy']
        dinamica.crestere_vanzari_yoy.sparkline_labels = sparkline_labels
        dinamica.crestere_achizitii_yoy.sparkline_data = historical_data['dinamica']['crestere_achizitii_yoy']
        dinamica.crestere_achizitii_yoy.sparkline_labels = sparkline_labels
        dinamica.marja_implicita.sparkline_data = historical_data['dinamica']['marja_implicita']
        dinamica.marja_implicita.sparkline_labels = sparkline_labels

        # Actualizăm Altman Z-Score cu sparkline data
        altman_zscore.zscore.sparkline_data = historical_data['altman_zscore']['zscore']
        altman_zscore.zscore.sparkline_labels = sparkline_labels
        altman_zscore.x1.sparkline_data = historical_data['altman_zscore']['x1']
        altman_zscore.x1.sparkline_labels = sparkline_labels
        altman_zscore.x2.sparkline_data = historical_data['altman_zscore']['x2']
        altman_zscore.x2.sparkline_labels = sparkline_labels
        altman_zscore.x3.sparkline_data = historical_data['altman_zscore']['x3']
        altman_zscore.x3.sparkline_labels = sparkline_labels
        altman_zscore.x4.sparkline_data = historical_data['altman_zscore']['x4']
        altman_zscore.x4.sparkline_labels = sparkline_labels

        # Actualizăm indicatorii de profitabilitate cu sparkline data
        profitabilitate.cifra_afaceri.sparkline_data = historical_data['profitabilitate']['cifra_afaceri']
        profitabilitate.cifra_afaceri.sparkline_labels = sparkline_labels
        profitabilitate.cheltuieli_totale.sparkline_data = historical_data['profitabilitate']['cheltuieli_totale']
        profitabilitate.cheltuieli_totale.sparkline_labels = sparkline_labels
        profitabilitate.profit_brut.sparkline_data = historical_data['profitabilitate']['profit_brut']
        profitabilitate.profit_brut.sparkline_labels = sparkline_labels
        profitabilitate.marja_profit_brut.sparkline_data = historical_data['profitabilitate']['marja_profit_brut']
        profitabilitate.marja_profit_brut.sparkline_labels = sparkline_labels
        profitabilitate.roa.sparkline_data = historical_data['profitabilitate']['roa']
        profitabilitate.roa.sparkline_labels = sparkline_labels
        profitabilitate.roe.sparkline_data = historical_data['profitabilitate']['roe']
        profitabilitate.roe.sparkline_labels = sparkline_labels

        # Actualizăm indicatorii de solvabilitate cu sparkline data
        solvabilitate.activ_net_contabil.sparkline_data = historical_data['solvabilitate']['activ_net_contabil']
        solvabilitate.activ_net_contabil.sparkline_labels = sparkline_labels
        solvabilitate.rata_anc_capital.sparkline_data = historical_data['solvabilitate']['rata_anc_capital']
        solvabilitate.rata_anc_capital.sparkline_labels = sparkline_labels

        # FIX: Sincronizare ultima valoare sparkline cu valoarea curentă calculată
        # Aceasta rezolvă inconsistențele când cache-ul pentru indicatori curenți
        # se reîmprospătează mai des decât cache-ul pentru istoric (sparklines)
        def sync_last_sparkline_value(indicator_obj, attr_name):
            """Înlocuiește ultima valoare din sparkline cu valoarea curentă calculată"""
            indicator = getattr(indicator_obj, attr_name, None)
            if indicator and hasattr(indicator, 'sparkline_data') and indicator.sparkline_data:
                if hasattr(indicator, 'value') and indicator.value is not None:
                    indicator.sparkline_data[-1] = indicator.value

        # Sincronizăm toți indicatorii
        for ind_obj, attrs in [
            (lichiditate, ['lichiditate_curenta', 'lichiditate_imediata', 'lichiditate_vedere']),
            (eficienta, ['dso', 'dpo', 'cash_conversion_cycle', 'rata_incasare', 'rata_plata']),
            (risc, ['creante_restante_pct', 'creante_90plus_pct', 'datorii_restante_pct', 'raport_datorii_trezorerie']),
            (cash_flow, ['flux_net_lunar', 'cash_flow_ytd', 'flux_net_yoy_pct', 'acoperire_cash_flow']),
            (dinamica, ['crestere_vanzari_yoy', 'crestere_achizitii_yoy', 'marja_implicita']),
            (altman_zscore, ['zscore', 'x1', 'x2', 'x3', 'x4']),
            (profitabilitate, ['cifra_afaceri', 'cheltuieli_totale', 'profit_brut', 'marja_profit_brut', 'roa', 'roe']),
            (solvabilitate, ['activ_net_contabil', 'rata_anc_capital']),
        ]:
            for attr in attrs:
                sync_last_sparkline_value(ind_obj, attr)

        # Construim răspunsul final
        response = FinancialIndicatorsResponse(
            lichiditate=lichiditate,
            eficienta=eficienta,
            risc=risc,
            cash_flow=cash_flow,
            dinamica=dinamica,
            altman_zscore=altman_zscore,
            profitabilitate=profitabilitate,
            solvabilitate=solvabilitate
        )

        logger.info(
            f"Indicators with sparklines for company {company_id}, luna={luna}, an={an}: "
            f"Z-Score={altman_zscore.zscore.value} ({altman_zscore.zscore.status}), "
            f"ROA={profitabilitate.roa.value}% ({profitabilitate.roa.status}), "
            f"ANC={solvabilitate.activ_net_contabil.value} ({solvabilitate.activ_net_contabil.status})"
        )

        return response
