import re
import psycopg2
from psycopg2.extras import RealDictCursor
from fasthtml.common import *

# 1. CSS Global passado nos cabeçalhos da aplicação (evita renderizar a tag <style> a cada requisição HTMX)
css_personalizado = Style("""
/* Container da tabela para garantir os cantos arredondados sem vazamento */
body {
    overflow-x: hidden; /* Evita rolagem horizontal indesejada */
}
.tabela-container {
    border: 2px solid #0D6EFD !important;
    border-radius: 12px !important;
    overflow: hidden !important; /* Corta os cantos internos */
}

.tabela-com-moldura {
    width: 100% !important;
    border-collapse: separate !important; /* Permite cantos arredondados */
    border-spacing: 0 !important;
    margin: 0 !important;
}

/* Linha vertical separando cada coluna (em todas as células) */
.tabela-com-moldura th:not(:last-child),
.tabela-com-moldura td:not(:last-child) {
    border-right: 1px solid #ccc !important;
}

/* Linha horizontal para separar as linhas da tabela */
.tabela-com-moldura th, 
.tabela-com-moldura td {
    border-bottom: 1px solid #eee !important;
}

.tabela-com-moldura tr:last-child td {
    border-bottom: none !important; /* Remove a linha do fundo da última linha */
}

/* Títulos das colunas com a cor #0D6EFD */
.tabela-com-moldura th {
    color: #0D6EFD !important;
    font-weight: bold !important;
}
""")

# Inicialização do FastHTML injetando o CSS nos headers
app, rt = fast_app(hdrs=(css_personalizado,))

DB_CONFIG = {
    "dbname": "bdps01",
    "user": "postgres",
    "password": "ps@web",
    "host": "127.0.0.1",
    "port": 5432,
}

def formatar_documento(doc) -> str:
    """Aplica mascara de CNPJ/CPF e oculta quando for zero ou vazio (suporta float/double precision)."""
    if doc is None or doc == "":
        return ""
    
    # Se for float/double precision vindo do banco (ex: 1234567890.0)
    if isinstance(doc, float):
        # Se for zero ou NaN
        if doc == 0 or doc != doc:
            return ""
        # Converte para int para eliminar o decimal .0 antes de virar string
        doc_str = str(int(doc))
    else:
        doc_str = str(doc)
    
    # Remove qualquer caractere que nao seja numero
    apenas_numeros = re.sub(r'\D', '', doc_str)
    
    # Se nao houver numeros ou se for apenas zeros
    if not apenas_numeros or int(apenas_numeros) == 0:
        return ""
    
    # Formata CNPJ (14 digitos)
    if len(apenas_numeros) == 14:
        return f"{apenas_numeros[:2]}.{apenas_numeros[2:5]}.{apenas_numeros[5:8]}/{apenas_numeros[8:12]}-{apenas_numeros[12:]}"
    
    # Formata CPF (completando os zeros à esquerda perdidos pelo double precision)
    if len(apenas_numeros) <= 11:
        apenas_numeros = apenas_numeros.zfill(11)
        return f"{apenas_numeros[:3]}.{apenas_numeros[3:6]}.{apenas_numeros[6:9]}-{apenas_numeros[9:]}"
    
    return doc_str

def buscar_cliente(termo: str = ""):
    """Consulta os clientes na tabela clienteia."""
    termo_limpo = termo.strip()
    try:
        conn = psycopg2.connect(**DB_CONFIG)
        conn.set_client_encoding('WIN1252')
        cursor = conn.cursor(cursor_factory=RealDictCursor)

        query = """
            SELECT cl1codig AS "Codigo", cl1nomec AS "Nome", cl1cnpj AS "CNPJ", cl1cpf as "CPF" 
            FROM clienteia
            WHERE nomec ILIKE %s
            ORDER BY nomec 
            LIMIT 50;
        """
        parametro = (f"%{termo_limpo}%",)

        # Usando mogrify com tratamento seguro de decode para o print no terminal
        try:
            query_bytes = cursor.mogrify(query, parametro)
            # O errors='replace' impede que o terminal quebre caso venha um byte isolado
            print("\n--- QUERY SENDO EXECUTADA ---")
            print(query_bytes.decode('utf-8', errors='replace'))
            print("-----------------------------\n")
        except Exception as err_print:
            print(f"Aviso: Não foi possível imprimir a query formatada: {err_print}")

        cursor.execute(query, parametro)
        clientes = cursor.fetchall()

        cursor.close()
        conn.close()
        return clientes
    except Exception as e:
        print(f"Erro na consulta SQL: {e}")
        return []

def destacar_termo(texto: str, termo: str) -> str:
    """Destaca o termo buscado na tabela."""
    termo_limpo = termo.strip()
    if not termo_limpo or not texto:
        return str(texto)
    padrao = re.compile(f"({re.escape(termo_limpo)})", re.IGNORECASE)
    return padrao.sub(r"<strong>\1</strong>", str(texto))


def render_tabela_cl1(clientes, termo: str = ""):
    """Gera a tabela HTML com os botões de seleção e CNPJ/CPF formatados."""
    if not clientes:
        return P("Nenhum cliente encontrado.", style="color: gray; padding: 10px;")

    colunas = list(clientes[0].keys())
    header = Tr(*[Th(col.replace("_", " ").title()) for col in colunas])

    linhas = []
    for prod in clientes:
        celulas = []
        for col in colunas:
            valor_bruto = prod[col] if prod[col] is not None else ""
            
            # Formata CNPJ ou CPF antes de renderizar
            if col in ["CNPJ", "CPF"]:
                valor_original = formatar_documento(valor_bruto)
            else:
                valor_original = str(valor_bruto)

            valor_formatado = destacar_termo(valor_original, termo)

            if col == "Codigo":
                # Botão de imagem com dimensões cravadas para não quebrar layout no onerror
                botao_seleciona = A(
                    Button(
                        Img(
                            src=f"/static/{valor_original}.jpg",
                            alt=f"Código {valor_original}",
                            width="40",
                            height="40",
                            style="width: 40px; height: 40px; object-fit: cover; vertical-align: middle; border-radius: 6px;",
                            onerror="this.onerror=null; this.src='/static/logoia.jpg';",
                        ),
                        cls="outline",
                        style="margin-right: 10px; padding: 2px 8px; font-size: 0.85rem;",
                    ),
                    hx_get=f"/selecionar-codigo?codigo={valor_original}",
                    hx_target="#container-modal",
                )
                celulas.append(Td(botao_seleciona, NotStr(valor_formatado)))
            else:
                celulas.append(Td(NotStr(valor_formatado)))

        linhas.append(Tr(*celulas))

    # Tabela envolvida na Div com estilo explícito da moldura azul `#0D6EFD`
    return Div(
        Table(
            Thead(header),
            Tbody(*linhas),
            cls="striped tabela-com-moldura",
        ),
        cls="tabela-container",
        style="border: 2px solid #0D6EFD; border-radius: 12px; overflow: hidden;",
    )
