import logging

from datetime import date
from typing import Optional, Union
from core.database import get_mysql_db
from core.auth import require_fix_token
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import APIRouter, Depends, Query, status

logger = logging.getLogger(__name__)
from schemas.omie_contas_receber import OmieContaReceberResponse, OmieContaReceberBoletoResponse, OmieBoletoCompletoResponse
from services.omie_contas_receber import OmieContaReceberService, OmieContaReceberBoletoService, OmieBoletoCompletoService
from core.api_responses import build_success_payload, to_schema_dict, SuccessResponse, ErrorResponse

logger = logging.getLogger(__name__)

router = APIRouter(
    prefix="/contas-receber",
    tags=["Omie - Contas a Receber"],
)

@router.get(
    "",
    summary="Listar contas a receber da Omie",
    description="""
Consulta a tabela **omie_contaReceber** no banco de dados **MySQL (DataLake)**.

**⚠️ IMPORTANTE:** Esta rota consulta dados da **Omie** armazenados no **MySQL**, diferente das rotas do sistema Alerta Fiscal que consultam o **SQL Server**.

**Tabela:** `omie_contaReceber` (MySQL)

**Filtros suportados (todos opcionais):**
- `cnpj`: Filtra por CNPJ (busca parcial)
- `data_inicio`: Data inicial para filtro de vencimento (formato: YYYY-MM-DD)
- `data_fim`: Data final para filtro de vencimento (formato: YYYY-MM-DD)
- `status`: Filtra por status da conta

**Exemplos:**

1. **Buscar todas as contas a receber:**
```bash
curl -X GET 'http://localhost:8000/contas-receber' \
  -H 'Authorization: Bearer <TOKEN>'
```

2. **Buscar por CNPJ:**
```bash
curl -X GET 'http://localhost:8000/contas-receber?cnpj=12345678000190' \
  -H 'Authorization: Bearer <TOKEN>'
```

3. **Buscar por período de vencimento:**
```bash
curl -X GET 'http://localhost:8000/contas-receber?data_inicio=2024-01-01&data_fim=2024-12-31' \
  -H 'Authorization: Bearer <TOKEN>'
```

4. **Buscar por status:**
```bash
curl -X GET 'http://localhost:8000/contas-receber?status=Pendente' \
  -H 'Authorization: Bearer <TOKEN>'
```

**SQL Base:**
```sql
SELECT * FROM omie_contaReceber
WHERE 
  (cnpj LIKE '%{cnpj}%' OR :cnpj IS NULL)
  AND (data_vencimento >= :data_inicio OR :data_inicio IS NULL)
  AND (data_vencimento <= :data_fim OR :data_fim IS NULL)
  AND (status = :status OR :status IS NULL)
```
""",
    response_model=SuccessResponse,
    responses={
        200: {"description": "Lista de contas a receber"},
        401: {"description": "Credenciais inválidas ou ausentes", "model": ErrorResponse},
        500: {"description": "Erro interno", "model": ErrorResponse},
    },
)
async def listar_contas_receber(
    cnpj: Optional[str] = Query(None, description="Filtrar por CNPJ (busca parcial)", example="12345678000190"),
    data_inicio: Optional[date] = Query(None, description="Data inicial para filtro de vencimento (YYYY-MM-DD)", example="2024-01-01"),
    data_fim: Optional[date] = Query(None, description="Data final para filtro de vencimento (YYYY-MM-DD)", example="2024-12-31"),
    status: Optional[str] = Query(None, description="Filtrar por status", example="Pendente"),
    _: None = Depends(require_fix_token),
    db: AsyncSession = Depends(get_mysql_db),
):
    logger.info(f"Iniciando busca de contas a receber - CNPJ: {cnpj}, Data: {data_inicio} a {data_fim}, Status: {status}")
    
    try:
        items = await OmieContaReceberService.listar(
            db, 
            cnpj=cnpj, 
            data_inicio=data_inicio, 
            data_fim=data_fim, 
            status=status
        )
        
        data = []
        for item in items:
            try:
                converted = to_schema_dict(OmieContaReceberResponse, item)
                data.append(converted)
            except Exception as e:
                logger.error(f"Erro ao converter item para schema: {e}")
                raise
        
        qtd = len(data)
        filtros = []
        if cnpj:
            filtros.append(f"CNPJ contendo '{cnpj}'")
        if data_inicio:
            filtros.append(f"Vencimento a partir de '{data_inicio}'")
        if data_fim:
            filtros.append(f"Vencimento até '{data_fim}'")
        if status:
            filtros.append(f"Status '{status}'")
        
        sufixo = f" com filtros: {', '.join(filtros)}" if filtros else ""
        if qtd == 0:
            message = f"Nenhuma conta a receber encontrada{sufixo}"
        elif qtd == 1:
            message = f"1 conta a receber encontrada{sufixo}"
        else:
            message = f"{qtd} contas a receber encontradas{sufixo}"
        
        logger.info(f"Busca concluída com sucesso: {message}")
        return build_success_payload(data=data, message=message)
    
    except Exception as e:
        logger.error(f"Erro ao listar contas a receber: {e}", exc_info=True)
        raise

@router.get(
    "/boleto",
    summary="Listar boletos das contas a receber da Omie",
    description="""
Consulta a tabela **omie_contaReceber_boleto** no banco de dados **MySQL (DataLake)**.

**⚠️ IMPORTANTE:** Esta rota consulta dados da **Omie** armazenados no **MySQL**, diferente das rotas do sistema Alerta Fiscal que consultam o **SQL Server**.

**Tabela:** `omie_contaReceber_boleto` (MySQL)

**Filtros suportados (todos opcionais):**
- `codigo_lancamento`: Filtra por código do lançamento
- `data_inicio`: Data inicial para filtro de vencimento (formato: YYYY-MM-DD)
- `data_fim`: Data final para filtro de vencimento (formato: YYYY-MM-DD)
- `status`: Filtra por status do boleto

**Exemplos:**

1. **Buscar todos os boletos:**
```bash
curl -X GET 'http://localhost:8000/contas-receber/boleto' \
  -H 'Authorization: Bearer <TOKEN>'
```

2. **Buscar por código de lançamento:**
```bash
curl -X GET 'http://localhost:8000/contas-receber/boleto?codigo_lancamento=12345' \
  -H 'Authorization: Bearer <TOKEN>'
```

3. **Buscar por período de vencimento:**
```bash
curl -X GET 'http://localhost:8000/contas-receber/boleto?data_inicio=2024-01-01&data_fim=2024-12-31' \
  -H 'Authorization: Bearer <TOKEN>'
```

**SQL Base:**
```sql
SELECT * FROM omie_contaReceber_boleto
WHERE 
  (codigo_lancamento = :codigo_lancamento OR :codigo_lancamento IS NULL)
  AND (data_vencimento >= :data_inicio OR :data_inicio IS NULL)
  AND (data_vencimento <= :data_fim OR :data_fim IS NULL)
  AND (status = :status OR :status IS NULL)
```
""",
    response_model=SuccessResponse,
    responses={
        200: {"description": "Lista de boletos"},
        401: {"description": "Credenciais inválidas ou ausentes", "model": ErrorResponse},
        500: {"description": "Erro interno", "model": ErrorResponse},
    },
)
async def listar_boletos(
    codigo_lancamento: Optional[str] = Query(None, description="Filtrar por código do lançamento", example="12345"),
    data_inicio: Optional[date] = Query(None, description="Data inicial para filtro de vencimento (YYYY-MM-DD)", example="2024-01-01"),
    data_fim: Optional[date] = Query(None, description="Data final para filtro de vencimento (YYYY-MM-DD)", example="2024-12-31"),
    status: Optional[str] = Query(None, description="Filtrar por status", example="Pendente"),
    _: None = Depends(require_fix_token),
    db: AsyncSession = Depends(get_mysql_db),
):
    logger.info(f"Iniciando busca de boletos - Código Lançamento: {codigo_lancamento}, Data: {data_inicio} a {data_fim}, Status: {status}")
    
    try:
        items = await OmieContaReceberBoletoService.listar(
            db, 
            codigo_lancamento=codigo_lancamento, 
            data_inicio=data_inicio, 
            data_fim=data_fim, 
            status=status
        )
        
        data = []
        for item in items:
            try:
                converted = to_schema_dict(OmieContaReceberBoletoResponse, item)
                data.append(converted)
            except Exception as e:
                logger.error(f"Erro ao converter item para schema: {e}")
                raise
        
        qtd = len(data)
        filtros = []
        if codigo_lancamento:
            filtros.append(f"Código Lançamento '{codigo_lancamento}'")
        if data_inicio:
            filtros.append(f"Vencimento a partir de '{data_inicio}'")
        if data_fim:
            filtros.append(f"Vencimento até '{data_fim}'")
        if status:
            filtros.append(f"Status '{status}'")
        
        sufixo = f" com filtros: {', '.join(filtros)}" if filtros else ""
        if qtd == 0:
            message = f"Nenhum boleto encontrado{sufixo}"
        elif qtd == 1:
            message = f"1 boleto encontrado{sufixo}"
        else:
            message = f"{qtd} boletos encontrados{sufixo}"
        
        logger.info(f"Busca concluída com sucesso: {message}")
        return build_success_payload(data=data, message=message)
    
    except Exception as e:
        logger.error(f"Erro ao listar boletos: {e}", exc_info=True)
        raise

@router.get(
    "/boleto/completo",
    summary="Listar boletos completos com dados da empresa e vencimento",
    description="""
Consulta **boletos com JOIN** nas tabelas **omie_contaReceber_boleto** e **omie_contaReceber** no banco de dados **MySQL (DataLake)**.

**⚠️ IMPORTANTE:** Esta rota retorna dados combinados de ambas as tabelas, incluindo:
- **Data de emissão do boleto** (`dDtEmBol` da tabela `omie_contaReceber_boleto`)
- **Data de vencimento** (`data_vencimento` da tabela `omie_contaReceber`)
- **CNPJ da empresa** (`cnpj` da tabela `omie_contaReceber`)
- Outros dados relevantes de ambas as tabelas

**Tabelas:** `omie_contaReceber_boleto` + `omie_contaReceber` (MySQL) com JOIN

**Filtros suportados (todos opcionais):**
- `cnpj`: Filtra por CNPJ da empresa (busca parcial)
- `data_vencimento_inicio`: Data inicial para filtro de vencimento (formato: YYYY-MM-DD)
- `data_vencimento_fim`: Data final para filtro de vencimento (formato: YYYY-MM-DD)
- `data_emissao_boleto_inicio`: Data inicial para filtro de emissão do boleto (formato: YYYY-MM-DD)
- `data_emissao_boleto_fim`: Data final para filtro de emissão do boleto (formato: YYYY-MM-DD)
- `status_titulo`: Filtra por status do título
- `pago`: Filtra por status de pagamento (true = apenas pagos, false = apenas não pagos)

**Exemplos:**

1. **Buscar todos os boletos completos:**
```bash
curl -X GET 'http://localhost:8000/contas-receber/boleto/completo' \
  -H 'Authorization: Bearer <TOKEN>'
```

2. **Buscar por CNPJ da empresa:**
```bash
curl -X GET 'http://localhost:8000/contas-receber/boleto/completo?cnpj=12345678000190' \
  -H 'Authorization: Bearer <TOKEN>'
```

3. **Buscar por período de vencimento:**
```bash
curl -X GET 'http://localhost:8000/contas-receber/boleto/completo?data_vencimento_inicio=2024-01-01&data_vencimento_fim=2024-12-31' \
  -H 'Authorization: Bearer <TOKEN>'
```

4. **Buscar por período de emissão do boleto:**
```bash
curl -X GET 'http://localhost:8000/contas-receber/boleto/completo?data_emissao_boleto_inicio=2024-01-01&data_emissao_boleto_fim=2024-12-31' \
  -H 'Authorization: Bearer <TOKEN>'
```

5. **Buscar por CNPJ e período de vencimento:**
```bash
curl -X GET 'http://localhost:8000/contas-receber/boleto/completo?cnpj=12345678000190&data_vencimento_inicio=2024-01-01&data_vencimento_fim=2024-12-31' \
  -H 'Authorization: Bearer <TOKEN>'
```

6. **Buscar apenas boletos PAGOS:**
```bash
curl -X GET 'http://localhost:8000/contas-receber/boleto/completo?pago=true' \
  -H 'Authorization: Bearer <TOKEN>'
```

7. **Buscar apenas boletos NÃO PAGOS:**
```bash
curl -X GET 'http://localhost:8000/contas-receber/boleto/completo?pago=false' \
  -H 'Authorization: Bearer <TOKEN>'
```

8. **Buscar boletos não pagos de uma empresa específica:**
```bash
curl -X GET 'http://localhost:8000/contas-receber/boleto/completo?cnpj=12345678000190&pago=false' \
  -H 'Authorization: Bearer <TOKEN>'
```

**SQL Base:**
```sql
SELECT 
    b.codigo_lancamento_omie,
    b.dDtEmBol as data_emissao_boleto,
    b.cNumBoleto as numero_boleto,
    b.cCodBarras as codigo_barras,
    b.cLinkBoleto as link_boleto,
    b.cCodStatus as status_boleto,
    b.cDesStatus as descricao_status,
    c.cnpj,
    c.data_vencimento,
    c.data_emissao,
    c.valor_documento,
    c.numero_documento,
    c.status_titulo,
    c.codigo_cliente_fornecedor
FROM omie_contaReceber_boleto b
INNER JOIN omie_contaReceber c 
    ON b.codigo_lancamento_omie = c.codigo_lancamento_omie
WHERE 
    (c.cnpj LIKE '%{cnpj}%' OR :cnpj IS NULL)
    AND (c.data_vencimento >= :data_vencimento_inicio OR :data_vencimento_inicio IS NULL)
    AND (c.data_vencimento <= :data_vencimento_fim OR :data_vencimento_fim IS NULL)
    AND (b.dDtEmBol >= :data_emissao_boleto_inicio OR :data_emissao_boleto_inicio IS NULL)
    AND (b.dDtEmBol <= :data_emissao_boleto_fim OR :data_emissao_boleto_fim IS NULL)
    AND (c.status_titulo = :status_titulo OR :status_titulo IS NULL)
    AND (
        (:pago IS NULL) OR
        (:pago = true AND (c.data_pagamento IS NOT NULL OR c.valor_pago > 0)) OR
        (:pago = false AND c.data_pagamento IS NULL AND (c.valor_pago IS NULL OR c.valor_pago = 0))
    )
```
""",
    response_model=SuccessResponse,
    responses={
        200: {"description": "Lista de boletos completos"},
        401: {"description": "Credenciais inválidas ou ausentes", "model": ErrorResponse},
        500: {"description": "Erro interno", "model": ErrorResponse},
    },
)
async def listar_boletos_completos(
    cnpj: Optional[str] = Query(None, description="Filtrar por CNPJ da empresa (busca parcial)", example="12345678000190"),
    data_vencimento_inicio: Optional[date] = Query(None, description="Data inicial para filtro de vencimento (YYYY-MM-DD)", example="2024-01-01"),
    data_vencimento_fim: Optional[date] = Query(None, description="Data final para filtro de vencimento (YYYY-MM-DD)", example="2024-12-31"),
    data_emissao_boleto_inicio: Optional[str] = Query(None, description="Data inicial para filtro de emissão do boleto (YYYY-MM-DD). Deixe vazio ou omita para não filtrar.", example="2024-01-01"),
    data_emissao_boleto_fim: Optional[str] = Query(None, description="Data final para filtro de emissão do boleto (YYYY-MM-DD). Deixe vazio ou omita para não filtrar.", example="2024-12-31"),
    status_titulo: Optional[str] = Query(None, description="Filtrar por status do título", example="Pendente"),
    pago: Optional[bool] = Query(None, description="Filtrar por status de pagamento (true = apenas pagos, false = apenas não pagos)", example=True),
    _: None = Depends(require_fix_token),
    db: AsyncSession = Depends(get_mysql_db),
):
    # Converte strings vazias para None e strings válidas para date
    data_emissao_boleto_inicio_parsed: Optional[date] = None
    data_emissao_boleto_fim_parsed: Optional[date] = None
    
    if data_emissao_boleto_inicio and data_emissao_boleto_inicio.strip():
        try:
            data_emissao_boleto_inicio_parsed = date.fromisoformat(data_emissao_boleto_inicio.strip())
        except (ValueError, AttributeError):
            logger.warning(f"Data de emissão boleto início inválida: {data_emissao_boleto_inicio}")
    
    if data_emissao_boleto_fim and data_emissao_boleto_fim.strip():
        try:
            data_emissao_boleto_fim_parsed = date.fromisoformat(data_emissao_boleto_fim.strip())
        except (ValueError, AttributeError):
            logger.warning(f"Data de emissão boleto fim inválida: {data_emissao_boleto_fim}")
    
    # Usa as datas parseadas
    data_emissao_boleto_inicio = data_emissao_boleto_inicio_parsed
    data_emissao_boleto_fim = data_emissao_boleto_fim_parsed
    logger.info(
        f"Iniciando busca de boletos completos - "
        f"CNPJ: {cnpj}, "
        f"Vencimento: {data_vencimento_inicio} a {data_vencimento_fim}, "
        f"Emissão Boleto: {data_emissao_boleto_inicio} a {data_emissao_boleto_fim}, "
        f"Status: {status_titulo}, "
        f"Pago: {pago}"
    )
    
    try:
        items = await OmieBoletoCompletoService.listar_completo(
            db,
            cnpj=cnpj,
            data_vencimento_inicio=data_vencimento_inicio,
            data_vencimento_fim=data_vencimento_fim,
            data_emissao_boleto_inicio=data_emissao_boleto_inicio,
            data_emissao_boleto_fim=data_emissao_boleto_fim,
            status_titulo=status_titulo,
            pago=pago,
        )
        
        # Converter Row objects para dicionários
        data = []
        for item in items:
            try:
                # Row object do SQLAlchemy pode ser acessado como atributo
                # Acessa diretamente os atributos do Row
                data_pagamento = item.data_pagamento if hasattr(item, 'data_pagamento') else None
                valor_pago = item.valor_pago if hasattr(item, 'valor_pago') else None
                status_titulo = item.status_titulo if hasattr(item, 'status_titulo') else None
                valor_documento = item.valor_documento if hasattr(item, 'valor_documento') else None
                
                # Log para debug se os valores estão vindo NULL
                if data_pagamento is None and valor_pago is None:
                    logger.debug(f"Registro {getattr(item, 'codigo_lancamento_omie', 'N/A')}: data_pagamento e valor_pago estão NULL, mas status_titulo={status_titulo}")
                
                # Determina se foi pago baseado em:
                # 1. data_pagamento preenchida OU
                # 2. valor_pago >= valor_documento OU
                # 3. status_titulo indica pagamento
                status_pago = False
                if status_titulo:
                    status_upper = str(status_titulo).upper()
                    status_pago = status_upper in [
                        'RECEBIDO', 'PAGO', 'BAIXADO', 'LIQUIDADO', 
                        'RECEBIDO PARCIALMENTE', 'PAGO PARCIALMENTE'
                    ]
                
                foi_pago = (
                    data_pagamento is not None or 
                    (valor_pago is not None and valor_documento is not None and float(valor_pago) >= float(valor_documento)) or
                    status_pago
                )
                
                # Usa os valores calculados (que nunca são NULL quando necessário)
                valor_pago_final = float(valor_pago) if valor_pago is not None else 0.0
                # Se status indica pago mas valor_pago é 0, usa valor_documento
                if foi_pago and valor_pago_final == 0 and valor_documento:
                    valor_pago_final = float(valor_documento)
                
                item_dict = {
                    "codigo_lancamento_omie": item.codigo_lancamento_omie,
                    "data_emissao_boleto": item.data_emissao_boleto,
                    "numero_boleto": item.numero_boleto,
                    "codigo_barras": item.codigo_barras,
                    "link_boleto": item.link_boleto,
                    "status_boleto": item.status_boleto,
                    "descricao_status": item.descricao_status,
                    "cnpj": item.cnpj,
                    "data_vencimento": item.data_vencimento,
                    "data_emissao": item.data_emissao,
                    "valor_documento": float(item.valor_documento) if item.valor_documento else 0.0,
                    "numero_documento": item.numero_documento,
                    "status_titulo": item.status_titulo,
                    "codigo_cliente_fornecedor": item.codigo_cliente_fornecedor,
                    "data_pagamento": data_pagamento,
                    "valor_pago": valor_pago_final,  # Sempre presente, nunca NULL
                    "pago": foi_pago,
                    # Dados do cliente que pagou
                    "codigo_cliente_omie": getattr(item, 'codigo_cliente_omie', None),
                    "cnpj_cliente": getattr(item, 'cnpj_cliente', None),
                    "razao_social_cliente": getattr(item, 'razao_social_cliente', None),
                    "nome_fantasia_cliente": getattr(item, 'nome_fantasia_cliente', None),
                }
                data.append(item_dict)
            except Exception as e:
                logger.error(f"Erro ao converter item para dicionário: {e}", exc_info=True)
                # Log adicional para debug
                logger.debug(f"Item type: {type(item)}, Item repr: {repr(item)[:200]}")
                raise
        
        qtd = len(data)
        filtros = []
        if cnpj:
            filtros.append(f"CNPJ contendo '{cnpj}'")
        if data_vencimento_inicio:
            filtros.append(f"Vencimento a partir de '{data_vencimento_inicio}'")
        if data_vencimento_fim:
            filtros.append(f"Vencimento até '{data_vencimento_fim}'")
        if data_emissao_boleto_inicio:
            filtros.append(f"Emissão boleto a partir de '{data_emissao_boleto_inicio}'")
        if data_emissao_boleto_fim:
            filtros.append(f"Emissão boleto até '{data_emissao_boleto_fim}'")
        if status_titulo:
            filtros.append(f"Status '{status_titulo}'")
        if pago is not None:
            filtros.append(f"Pago: {'Sim' if pago else 'Não'}")
        
        sufixo = f" com filtros: {', '.join(filtros)}" if filtros else ""
        if qtd == 0:
            message = f"Nenhum boleto completo encontrado{sufixo}"
        elif qtd == 1:
            message = f"1 boleto completo encontrado{sufixo}"
        else:
            message = f"{qtd} boletos completos encontrados{sufixo}"
        
        logger.info(f"Busca concluída com sucesso: {message}")
        return build_success_payload(data=data, message=message)
    
    except Exception as e:
        logger.error(f"Erro ao listar boletos completos: {e}", exc_info=True)
        raise

