"""
Service pentru logica facturi - Portează query-urile din aplicația Flask
"""
# import sys  # Removed - no longer needed
import os

from shared.database.oracle_pool import oracle_pool
from typing import List, Tuple
from ..models.invoice import Invoice, InvoiceFilter, InvoiceListResponse, InvoiceSummary
from ..cache.decorators import cached
from decimal import Decimal
import logging

logger = logging.getLogger(__name__)

class InvoiceService:
    """Service pentru gestionarea facturilor"""

    @staticmethod
    @cached(cache_type='schema', key_params=['company_id'])
    async def _get_schema(company_id: int) -> str:
        """Obține schema pentru company_id (CACHED PERMANENT)"""
        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='invoices', key_params=['filter_params', 'username'])
    async def get_invoices(filter_params: InvoiceFilter, username: str) -> InvoiceListResponse:
        """
        Obține lista de facturi - Query simplu pentru afișare în tabel (CACHED 10 min)
        """
        company_id = int(filter_params.company)
        schema = await InvoiceService._get_schema(company_id)

        async with oracle_pool.get_connection() as connection:
            with connection.cursor() as cursor:
                
                # Determină conturile în funcție de partner_type
                if filter_params.partner_type == "CLIENTI":
                    conturi = "'4111', '461'"
                elif filter_params.partner_type == "FURNIZORI":
                    conturi = "'401', '404', '462'"
                else:
                    conturi = "'4111'"  # default
                
                # Determine period to use: from params or MAX from calendar
                if filter_params.luna and filter_params.an:
                    period_condition = "vp.an = :an AND vp.luna = :luna"
                    use_param_period = True
                else:
                    period_condition = f"""vp.an = (SELECT anul FROM {schema}.calendar WHERE anul*12+luna = (SELECT MAX(anul*12+luna) FROM {schema}.calendar))
                  AND vp.luna = (SELECT luna FROM {schema}.calendar WHERE anul*12+luna = (SELECT MAX(anul*12+luna) FROM {schema}.calendar))"""
                    use_param_period = False

                # Query cu calculele corecte pentru solduri
                base_query = f"""
                SELECT
                  vp.NUME,
                  vp.NRACT,
                  vp.DATAACT,
                  vp.DATASCAD,
                  vp.CONTRACT,
                  vp.COD_FISCAL,
                  vp.REG_COMERT,
                  CASE
                    WHEN vp.CONT IN ('4111','461') THEN vp.PRECDEB + vp.DEBIT  -- Total facturat clienți
                    WHEN vp.CONT IN ('401','404','462') THEN vp.PRECCRED + vp.CREDIT  -- Total facturat furnizori
                  END as total_facturat,
                  CASE
                    WHEN vp.CONT IN ('4111','461') THEN vp.PRECCRED + vp.CREDIT  -- Încasat clienți
                    WHEN vp.CONT IN ('401','404','462') THEN vp.PRECDEB + vp.DEBIT  -- Achitat furnizori
                  END as achitat,
                  CASE
                    WHEN vp.CONT IN ('4111','461') THEN
                      (vp.PRECDEB + vp.DEBIT) - (vp.PRECCRED + vp.CREDIT)  -- Sold clienți
                    WHEN vp.CONT IN ('401','404','462') THEN
                      (vp.PRECCRED + vp.CREDIT) - (vp.PRECDEB + vp.DEBIT)  -- Sold furnizori
                  END as sold,
                  vp.CONT,
                  NVL(vp.NUME_VAL, 'RON') as valuta,
                  CASE
                    WHEN vp.DATASCAD < SYSDATE THEN 'restant'
                    ELSE 'in_termen'
                  END as status
                FROM {schema}.vireg_parteneri vp
                WHERE {period_condition}
                  AND (
                    (:partner_type = 'CLIENTI' AND vp.cont IN ('4111', '461'))
                    OR
                    (:partner_type = 'FURNIZORI' AND vp.cont IN ('401', '404', '462'))
                  )
                """

                params = {'partner_type': filter_params.partner_type}

                # Add period params if using explicit period
                if use_param_period:
                    params['an'] = filter_params.an
                    params['luna'] = filter_params.luna
                
                if filter_params.partner_name:
                    base_query += " AND UPPER(vp.nume) LIKE UPPER(:partner_name)"
                    params['partner_name'] = f"%{filter_params.partner_name}%"

                if filter_params.cont:
                    base_query += " AND vp.cont = :cont"
                    params['cont'] = filter_params.cont

                if filter_params.min_amount:
                    base_query += " AND total_facturat >= :min_amount"
                    params['min_amount'] = filter_params.min_amount
                    
                if filter_params.max_amount:
                    base_query += " AND total_facturat <= :max_amount"
                    params['max_amount'] = filter_params.max_amount
                
                if filter_params.only_unpaid:
                    # Nu putem folosi aliasul "sold" în WHERE în Oracle, trebuie să repetăm calculul
                    base_query += """ AND (
                        CASE
                            WHEN vp.CONT IN ('4111','461') THEN
                                (vp.PRECDEB + vp.DEBIT) - (vp.PRECCRED + vp.CREDIT)
                            WHEN vp.CONT IN ('401','404','462') THEN
                                (vp.PRECCRED + vp.CREDIT) - (vp.PRECDEB + vp.DEBIT)
                        END
                    ) > 0"""
                
                # Count total pentru paginare
                count_query = f"SELECT COUNT(*) FROM ({base_query})"
                cursor.execute(count_query, params)
                total_count = cursor.fetchone()[0]

                # Query pentru TOTAL SOLD din TOATE facturile filtrate (nu doar pagina curentă)
                total_sold_query = f"""
                    SELECT NVL(SUM(sold), 0) as total_sold
                    FROM ({base_query})
                """
                cursor.execute(total_sold_query, params)
                total_sold_result = cursor.fetchone()
                total_sold_all = Decimal(str(total_sold_result[0])) if total_sold_result else Decimal('0.00')

                # Get accounting period - use params if provided, else from calendar
                if use_param_period:
                    accounting_period = {
                        'an': filter_params.an,
                        'luna': filter_params.luna
                    }
                else:
                    period_query = f"""
                        SELECT anul, luna
                        FROM {schema}.calendar
                        WHERE anul*12+luna = (SELECT MAX(anul*12+luna) FROM {schema}.calendar)
                    """
                    cursor.execute(period_query)
                    period_result = cursor.fetchone()
                    accounting_period = {
                        'an': period_result[0] if period_result else None,
                        'luna': period_result[1] if period_result else None
                    }

                # Adaugă ORDER BY și paginare - Ordonare cronologică (DATAACT, NRACT, NUME)
                base_query += " ORDER BY vp.DATAACT ASC, vp.NRACT ASC, vp.NUME"

                # Paginare Oracle
                offset = (filter_params.page - 1) * filter_params.page_size
                limit = offset + filter_params.page_size
                paginated_query = f"""
                    SELECT * FROM (
                        SELECT ROWNUM as rn, t.* FROM ({base_query}) t WHERE ROWNUM <= :limit
                    ) WHERE rn > :offset
                """
                params['offset'] = offset
                params['limit'] = limit

                cursor.execute(paginated_query, params)
                rows = cursor.fetchall()
                
                # Procesează rezultatele cu structura nouă
                invoices = []
                total_amount = Decimal('0.00')
                
                for row in rows:
                    # Skip ROWNUM, extrage valorile din query-ul nou
                    nume = row[1]
                    nract = row[2]
                    dataact = row[3]
                    datascad = row[4]
                    contract = row[5]
                    cod_fiscal = row[6]
                    reg_comert = row[7]
                    total_facturat = Decimal(str(row[8] or 0))
                    achitat = Decimal(str(row[9] or 0))
                    sold = Decimal(str(row[10] or 0))
                    cont = row[11]
                    valuta = row[12] or 'RON'
                    status = row[13]

                    invoice_data = {
                        'nume': nume or '',
                        'nract': nract or 0,
                        'dataact': dataact,
                        'datascad': datascad,
                        'contract': contract,
                        'cod_fiscal': cod_fiscal,
                        'reg_comert': reg_comert,
                        'cont': cont,
                        'totctva': total_facturat,
                        'achitat': achitat,
                        'soldfinal': sold,
                        'valuta': valuta
                    }
                    
                    invoice = Invoice(**invoice_data)
                    invoices.append(invoice)
                    total_amount += total_facturat
                
                return InvoiceListResponse(
                    invoices=invoices,
                    total_count=total_count,
                    filtered_count=len(invoices),
                    total_amount=total_amount,
                    page=filter_params.page,
                    page_size=filter_params.page_size,
                    has_more=len(invoices) == filter_params.page_size,
                    accounting_period=accounting_period,
                    # Total sold din TOATE facturile filtrate
                    total_sold_all=total_sold_all
                )
    
    @staticmethod
    async def get_invoice_details(company: str, invoice_number: str, username: str) -> Invoice:
        """
        Obține detaliile unei facturi specifice
        """
        async with oracle_pool.get_connection() as connection:
            with connection.cursor() as cursor:
                # Obține schema din v_nom_firme bazat pe id_firma
                company_id = int(company)
                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 nu a fost găsită pentru id_firma {company_id}")
                
                schema = schema_result[0]
                
                # Query simplu pentru detalii factură
                detail_query = f"""
                SELECT 
                    NUME,
                    NRACT,
                    DATAACT,
                    DATASCAD,
                    CONTRACT,
                    COD_FISCAL,
                    REG_COMERT,
                    PRECDEB,
                    PRECCRED,
                    DEBIT,
                    CREDIT,
                    CONT
                FROM {schema}.vireg_parteneri
                WHERE nract = :invoice_number
                  AND an = (select anul from {schema}.calendar where anul*12+luna = (select max(anul*12+luna) as anmax from {schema}.calendar))
                  AND luna = (select luna from {schema}.calendar where anul*12+luna = (select max(anul*12+luna) as anmax from {schema}.calendar))
                """
                
                cursor.execute(detail_query, {'invoice_number': invoice_number})
                row = cursor.fetchone()
                
                if not row:
                    raise ValueError(f"Factura {invoice_number} nu a fost găsită")
                
                # Extrage valorile
                nume = row[0]
                nract = row[1]
                dataact = row[2]
                datascad = row[3]
                contract = row[4]
                cod_fiscal = row[5]
                reg_comert = row[6]
                precdeb = Decimal(str(row[7] or 0))
                preccred = Decimal(str(row[8] or 0))
                debit = Decimal(str(row[9] or 0))
                credit = Decimal(str(row[10] or 0))
                cont = row[11]
                
                # Calculează valorile în funcție de tipul contului
                if cont in ('4111', '461'):  # CLIENTI
                    totctva = precdeb + debit
                    achitat = preccred + credit
                    soldfinal = precdeb - preccred + debit - credit
                else:  # FURNIZORI
                    totctva = preccred + credit
                    achitat = precdeb + debit
                    soldfinal = preccred - precdeb + credit - debit
                
                invoice_data = {
                    'nume': nume or '',
                    'nract': nract or 0,
                    'dataact': dataact,
                    'datascad': datascad,
                    'contract': contract,
                    'cod_fiscal': cod_fiscal,
                    'reg_comert': reg_comert,
                    'totctva': totctva,
                    'achitat': achitat,
                    'soldfinal': soldfinal
                }
                
                return Invoice(**invoice_data)