"""
Service pentru Trial Balance (Balanță de Verificare) - Query VBAL VIEW
Refactored to use caching system for optimal performance
"""
# import sys  # Removed - no longer needed
import os

from shared.database.oracle_pool import oracle_pool
from typing import Dict, Any
from ..models.trial_balance import (
    TrialBalanceItem,
    TrialBalanceFilters,
    TrialBalancePagination,
    TrialBalanceResponse
)
from ..cache.decorators import cached
from decimal import Decimal
import math
import logging

logger = logging.getLogger(__name__)


class TrialBalanceService:
    """Service pentru gestionarea balanței de verificare cu cache"""

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

        This is cached permanently because company schemas rarely change.
        """
        async with oracle_pool.get_connection() 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
    @cached(cache_type='trial_balance', key_params=['company_id', 'luna', 'an', 'cont_filter',
                                                      'denumire_filter', 'sort_by', 'sort_order',
                                                      'page', 'page_size', 'username'])
    async def get_trial_balance(
        company_id: int,
        luna: int,
        an: int,
        cont_filter: str | None,
        denumire_filter: str | None,
        sort_by: str,
        sort_order: str,
        page: int,
        page_size: int,
        username: str
    ) -> Dict[str, Any]:
        """
        Obține balanța de verificare sintetică (CACHED 10 min)

        Cache key includes all filter parameters to ensure unique cache entries
        for different query variations.

        Args:
            company_id: ID firmei
            luna: Luna (1-12)
            an: Anul
            cont_filter: Filtru număr cont (optional)
            denumire_filter: Filtru denumire cont (optional)
            sort_by: Coloană pentru sortare
            sort_order: Ordinea sortării (asc/desc)
            page: Pagina
            page_size: Mărimea paginii
            username: Username pentru cache tracking

        Returns:
            Dictionary cu items, pagination, filters_applied
        """
        # Get schema (cached separately)
        schema = await TrialBalanceService._get_schema(company_id)

        # Validate sort_order
        if sort_order.lower() not in ['asc', 'desc']:
            sort_order = 'asc'

        # Validate sort_by (prevent SQL injection)
        valid_sort_columns = ['CONT', 'DENUMIRE', 'PRECDEB', 'PRECCRED',
                              'RULDEB', 'RULCRED', 'SOLDDEB', 'SOLDCRED']
        if sort_by.upper() not in valid_sort_columns:
            sort_by = 'CONT'

        async with oracle_pool.get_connection() as connection:
            with connection.cursor() as cursor:
                # Build base query for VBAL VIEW
                base_query = f"""
                    SELECT
                        CONT,
                        NVL(DENUMIRE, '') as DENUMIRE,
                        NVL(PRECDEB, 0) as PRECDEB,
                        NVL(PRECCRED, 0) as PRECCRED,
                        NVL(RULDEB, 0) as RULDEB,
                        NVL(RULCRED, 0) as RULCRED,
                        NVL(SOLDDEB, 0) as SOLDDEB,
                        NVL(SOLDCRED, 0) as SOLDCRED
                    FROM {schema}.VBAL
                    WHERE AN = :an
                      AND LUNA = :luna
                """

                params = {
                    'an': an,
                    'luna': luna
                }

                # Add dynamic filters
                if cont_filter:
                    base_query += " AND CONT LIKE :cont_filter"
                    params['cont_filter'] = f"{cont_filter}%"

                if denumire_filter:
                    base_query += " AND UPPER(DENUMIRE) LIKE UPPER(:denumire_filter)"
                    params['denumire_filter'] = f"%{denumire_filter}%"

                # Count total for pagination
                count_query = f"SELECT COUNT(*) FROM ({base_query})"
                cursor.execute(count_query, params)
                total_count = cursor.fetchone()[0]

                # Query pentru TOTALURI din TOATE înregistrările filtrate (nu doar pagina curentă)
                totals_query = f"""
                    SELECT
                        NVL(SUM(PRECDEB), 0) as total_prec_deb,
                        NVL(SUM(PRECCRED), 0) as total_prec_cred,
                        NVL(SUM(RULDEB), 0) as total_rul_deb,
                        NVL(SUM(RULCRED), 0) as total_rul_cred,
                        NVL(SUM(SOLDDEB), 0) as total_sold_deb,
                        NVL(SUM(SOLDCRED), 0) as total_sold_cred
                    FROM ({base_query})
                """
                cursor.execute(totals_query, params)
                totals_row = cursor.fetchone()

                totals = {
                    "total_sold_precedent_debit": Decimal(str(totals_row[0])) if totals_row else Decimal('0.00'),
                    "total_sold_precedent_credit": Decimal(str(totals_row[1])) if totals_row else Decimal('0.00'),
                    "total_rulaj_lunar_debit": Decimal(str(totals_row[2])) if totals_row else Decimal('0.00'),
                    "total_rulaj_lunar_credit": Decimal(str(totals_row[3])) if totals_row else Decimal('0.00'),
                    "total_sold_final_debit": Decimal(str(totals_row[4])) if totals_row else Decimal('0.00'),
                    "total_sold_final_credit": Decimal(str(totals_row[5])) if totals_row else Decimal('0.00')
                }

                # Add sorting
                base_query += f" ORDER BY {sort_by.upper()} {sort_order.upper()}"

                # Pagination (Oracle ROWNUM with ORDER BY)
                offset = (page - 1) * page_size
                limit = offset + page_size

                paginated_query = f"""
                    SELECT * FROM (
                        SELECT a.*, ROWNUM rnum FROM (
                            {base_query}
                        ) a WHERE ROWNUM <= :limit
                    ) WHERE rnum > :offset
                """
                params['offset'] = offset
                params['limit'] = limit

                cursor.execute(paginated_query, params)
                rows = cursor.fetchall()

                # Process results
                # Index: CONT(0), DENUMIRE(1), PRECDEB(2), PRECCRED(3),
                #        RULDEB(4), RULCRED(5), SOLDDEB(6), SOLDCRED(7), rnum(8)
                items = []
                for row in rows:
                    item = TrialBalanceItem(
                        cont=row[0] or '',
                        denumire=row[1] or '',
                        sold_precedent_debit=Decimal(str(row[2] or 0)),
                        sold_precedent_credit=Decimal(str(row[3] or 0)),
                        rulaj_lunar_debit=Decimal(str(row[4] or 0)),
                        rulaj_lunar_credit=Decimal(str(row[5] or 0)),
                        sold_final_debit=Decimal(str(row[6] or 0)),
                        sold_final_credit=Decimal(str(row[7] or 0))
                    )
                    items.append(item.dict())

                # Calculate pagination
                total_pages = math.ceil(total_count / page_size) if page_size > 0 else 0

                # Build response
                return {
                    "items": items,
                    "pagination": {
                        "total_items": total_count,
                        "total_pages": total_pages,
                        "current_page": page,
                        "page_size": page_size
                    },
                    "filters_applied": {
                        "luna": luna,
                        "an": an,
                        "cont_filter": cont_filter,
                        "denumire_filter": denumire_filter
                    },
                    # Totaluri din TOATE înregistrările filtrate (nu doar pagina curentă)
                    "totals": totals
                }
