"""Service for fetching nomenclatures from Oracle (read-only)."""

from typing import List, Optional
from decimal import Decimal

from sqlmodel import select
from sqlalchemy.ext.asyncio import AsyncSession

from backend.modules.data_entry.schemas.receipt import (
    PartnerOption,
    AccountOption,
    CashRegisterOption,
    ExpenseTypeOption,
)
from backend.modules.data_entry.services.expense_types import EXPENSE_TYPES
from backend.modules.data_entry.db.models.nomenclature import SyncedSupplier, LocalSupplier, SyncedCashRegister


class NomenclatureService:
    """
    Service for fetching nomenclatures.

    In Phase 1 (MVP), some nomenclatures are hardcoded.
    In Phase 2, these will be fetched from Oracle.
    """

    @staticmethod
    async def get_partners(
        company_id: int,
        search: Optional[str] = None,
        session: Optional[AsyncSession] = None
    ) -> List[PartnerOption]:
        """
        Get partners (suppliers/customers) for a company.

        Returns synced suppliers from Oracle + local suppliers created from OCR.
        If no suppliers exist, returns empty list (frontend will trigger sync).
        """
        partners = []

        if not session:
            return partners

        # Get synced suppliers from Oracle
        stmt = select(SyncedSupplier).where(SyncedSupplier.company_id == company_id)
        if search:
            stmt = stmt.where(
                (SyncedSupplier.name.ilike(f"%{search}%")) |
                (SyncedSupplier.fiscal_code.ilike(f"%{search}%"))
            )
        stmt = stmt.order_by(SyncedSupplier.name)

        result = await session.execute(stmt)
        suppliers = result.scalars().all()

        for s in suppliers:
            partners.append(PartnerOption(
                name=s.name,
                fiscal_code=s.fiscal_code,
                address=s.address,
                source="oracle"
            ))

        # Always get local suppliers (not just when synced exist)
        local_stmt = select(LocalSupplier).where(LocalSupplier.company_id == company_id)
        if search:
            local_stmt = local_stmt.where(
                (LocalSupplier.name.ilike(f"%{search}%")) |
                (LocalSupplier.fiscal_code.ilike(f"%{search}%"))
            )
        local_stmt = local_stmt.order_by(LocalSupplier.name)

        local_result = await session.execute(local_stmt)
        local_suppliers = local_result.scalars().all()

        for l in local_suppliers:
            partners.append(PartnerOption(
                name=l.name,
                fiscal_code=l.fiscal_code,
                address=l.address,
                source="local"
            ))

        return partners

    @staticmethod
    async def get_accounts(company_id: int, prefix: Optional[str] = None) -> List[AccountOption]:
        """
        Get chart of accounts for a company.

        Phase 1: Returns common expense/income accounts.
        Phase 2: Will fetch from Oracle PLAN_CONTURI.
        """
        # Common accounts for expenses and receipts
        accounts = [
            # Expense accounts (Class 6)
            AccountOption(code="6022", name="Cheltuieli cu combustibilii"),
            AccountOption(code="6024", name="Cheltuieli materiale pentru ambalat"),
            AccountOption(code="6028", name="Alte cheltuieli cu materiale consumabile"),
            AccountOption(code="624", name="Cheltuieli cu transportul de bunuri si personal"),
            AccountOption(code="626", name="Cheltuieli postale si taxe telecomunicatii"),
            AccountOption(code="628", name="Alte cheltuieli cu serviciile executate de terti"),

            # VAT
            AccountOption(code="4426", name="TVA deductibila"),
            AccountOption(code="4427", name="TVA colectata"),

            # Cash and Bank (Class 5)
            AccountOption(code="5311", name="Casa in lei"),
            AccountOption(code="5121", name="Conturi la banci in lei"),

            # Income accounts (Class 7)
            AccountOption(code="7588", name="Alte venituri din exploatare"),
        ]

        if prefix:
            accounts = [a for a in accounts if a.code.startswith(prefix)]

        return accounts

    @staticmethod
    async def get_cash_registers(
        company_id: int,
        session: Optional[AsyncSession] = None
    ) -> List[CashRegisterOption]:
        """
        Get cash registers and bank accounts for a company.

        Phase 1: Returns default options.
        Phase 2: Returns synced data from SQLite (from Oracle sync).
        Phase 3: Will fetch live from Oracle NOM_CASE / NOM_BANCI.
        """
        # If session is provided, try to get from synced SQLite data
        if session:
            stmt = select(SyncedCashRegister).where(SyncedCashRegister.company_id == company_id)
            result = await session.execute(stmt)
            registers = result.scalars().all()

            if registers:
                return [
                    CashRegisterOption(id=r.id, name=r.name, account_code=r.account_code)
                    for r in registers
                ]

        # Fallback to default cash registers for Phase 1
        return [
            CashRegisterOption(id=1, name="Casa principala", account_code="5311"),
            CashRegisterOption(id=2, name="Cont BCR", account_code="5121"),
            CashRegisterOption(id=3, name="Cont BRD", account_code="5121"),
        ]

    @staticmethod
    async def get_expense_types() -> List[ExpenseTypeOption]:
        """
        Get predefined expense types with their accounting configuration.
        """
        return [
            ExpenseTypeOption(
                code=et.code,
                name=et.name,
                account_code=et.account_code,
                has_vat=et.has_vat,
                vat_percent=et.vat_percent,
            )
            for et in EXPENSE_TYPES.values()
        ]

    @staticmethod
    async def get_companies(username: str) -> List[dict]:
        """
        Get companies accessible by user.

        Phase 1: Returns mock data.
        Phase 2: Will fetch from shared auth based on user permissions.
        """
        # TODO: Integrate with shared auth to get user's companies
        return [
            {"id": 1, "name": "SC Test SRL", "cui": "RO12345678"},
            {"id": 2, "name": "SC Demo SA", "cui": "RO87654321"},
        ]

    # ============ Phase 2 Oracle Integration Methods ============

    @staticmethod
    async def _fetch_partners_oracle(company_id: int, search: Optional[str] = None) -> List[PartnerOption]:
        """
        Fetch partners from Oracle NOM_PARTENERI.

        Will be implemented in Phase 2.
        """
        # TODO: Implement using shared oracle_pool
        # Example query:
        # SELECT ID_PART, DEN_PART, COD_FISCAL
        # FROM {schema}.NOM_PARTENERI
        # WHERE DEN_PART LIKE :search
        raise NotImplementedError("Oracle integration pending - Phase 2")

    @staticmethod
    async def _fetch_accounts_oracle(company_id: int, prefix: Optional[str] = None) -> List[AccountOption]:
        """
        Fetch chart of accounts from Oracle PLAN_CONTURI.

        Will be implemented in Phase 2.
        """
        # TODO: Implement using shared oracle_pool
        raise NotImplementedError("Oracle integration pending - Phase 2")

    @staticmethod
    async def _fetch_cash_registers_oracle(company_id: int) -> List[CashRegisterOption]:
        """
        Fetch cash registers from Oracle NOM_CASE / NOM_BANCI.

        Will be implemented in Phase 2.
        """
        # TODO: Implement using shared oracle_pool
        raise NotImplementedError("Oracle integration pending - Phase 2")
