import os
import jwt
import psycopg2
from psycopg2.extras import DictCursor
from fastapi import HTTPException, Depends, Header
from datetime import datetime
from pytz import timezone
from cryptography.fernet import Fernet

APP_KEY = os.getenv("APP_KEY")
API_KEY = os.getenv("API_KEY")
SESSION_KEY = os.getenv("SESSION_KEY")
DB_HOST = os.getenv("POSTGRES_HOST")
DB_PORT = os.getenv("POSTGRES_PORT")
DB_NAME = os.getenv("POSTGRES_DB")
DB_USER = os.getenv("POSTGRES_USER")
DB_PASS = os.getenv("POSTGRES_PASSWORD")
SAO_PAULO_TZ = timezone('America/Sao_Paulo')

if not APP_KEY or not API_KEY or not SESSION_KEY:
    raise ValueError("As variáveis APP_KEY, API_KEY e SESSION_KEY devem ser definidas.")

fernet = Fernet(APP_KEY.encode())

def get_db_connection():
    try:
        return psycopg2.connect(dbname=DB_NAME, user=DB_USER, password=DB_PASS, host=DB_HOST, port=DB_PORT)
    except psycopg2.OperationalError as e:
        print(f"Erro ao conectar ao banco de dados: {e}")
        raise HTTPException(status_code=503, detail="Serviço de banco de dados indisponível.")

def encrypt_data(data: str) -> str: return fernet.encrypt(data.encode()).decode()
def decrypt_data(encrypted_data: str) -> str: return fernet.decrypt(encrypted_data.encode()).decode()

async def verify_api_key(x_api_key: str = Header(..., description="Chave de API.")):
    if x_api_key != API_KEY:
        raise HTTPException(status_code=401, detail="Chave de API inválida ou ausente.")

def to_sao_paulo_time(dt: datetime):
    """
    Um filtro Jinja2 para converter um datetime com fuso horário UTC
    para o fuso horário de São Paulo.
    """
    if not isinstance(dt, datetime):
        return dt
    
    return dt.astimezone(SAO_PAULO_TZ)

def register_session_logic(cookie_string: str):
    try:
        fgtsd_token_str = next((s.split('=')[1] for s in cookie_string.split('; ') if s.startswith('fgtsd_token=')), None)
        if not fgtsd_token_str:
            raise ValueError("O 'fgtsd_token' não foi encontrado na string de cookie.")
        
        decoded_token = jwt.decode(fgtsd_token_str, options={"verify_signature": False})
        cnpj = decoded_token.get("cnpj")
        nome_empresa = decoded_token.get("cnpj_nome")
        exp_timestamp = decoded_token.get("exp")

        if not all([cnpj, nome_empresa, exp_timestamp]):
            raise ValueError("JWT inválido. Faltam campos essenciais.")

        exp_datetime = datetime.fromtimestamp(exp_timestamp, tz=SAO_PAULO_TZ)
        encrypted_cookie = encrypt_data(cookie_string)
        
        conn = get_db_connection()
        try:
            with conn.cursor() as cur:
                query = """
                    INSERT INTO sessoes_fgts (cnpj, nome_empresa, cookies_completos, expira_em, status, ultima_renovacao)
                    VALUES (%s, %s, %s, %s, 'ativo', %s) ON CONFLICT (cnpj) DO UPDATE SET
                        nome_empresa = EXCLUDED.nome_empresa, cookies_completos = EXCLUDED.cookies_completos,
                        expira_em = EXCLUDED.expira_em, status = 'ativo', ultima_renovacao = EXCLUDED.ultima_renovacao, observacoes = NULL;
                """
                cur.execute(query, (cnpj, nome_empresa, encrypted_cookie, exp_datetime, datetime.now(SAO_PAULO_TZ)))
                conn.commit()
            return {"status": "sucesso", "cnpj": cnpj}
        finally:
            conn.close()
    except (ValueError, jwt.PyJWTError) as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        print(f"Erro inesperado no registro: {e}")
        raise HTTPException(status_code=500, detail="Ocorreu um erro interno no servidor.")
    
def get_session_by_cnpj_api(cnpj: str):
    conn = get_db_connection()
    try:
        with conn.cursor(cursor_factory=DictCursor) as cur:
            cur.execute("SELECT * FROM sessoes_fgts WHERE cnpj = %s;", (cnpj,))
            session_data = cur.fetchone()
        if not session_data:
            return None  # Retorna None ao invés de lançar exceção
        return session_data['id']
    finally:
        conn.close()
    
def register_customer_session_logic(cookie_string: str):
    
    try:
        fgtsd_token_str = next((s.split('=')[1] for s in cookie_string.split('; ') if s.startswith('fgtsd_token=')), None)
        if not fgtsd_token_str:
            raise ValueError("O 'fgtsd_token' não foi encontrado na string de cookie.")
        
        session_id = get_session_by_cnpj_api('36497467000136')
        if session_id is None:
            raise HTTPException(status_code=404, detail="Sessão da contabilidade não encontrada. É necessário fazer login primeiro.")
        
        # return {"status": "sucesso", "id_contabilidade": session_id}
    
        id_contabilidade = session_id
        decoded_token = jwt.decode(fgtsd_token_str, options={"verify_signature": False})
        cnpj = decoded_token.get("fgtsdigital.gov.br/ni_perfil")
        nome_empresa = decoded_token.get("fgtsdigital.gov.br/nome_perfil")
        exp_timestamp = decoded_token.get("exp")

        # return {"cnpj": cnpj, "nome_empresa": nome_empresa, "exp_timestamp": exp_timestamp, "session_id": session_id}

        if not all([cnpj, nome_empresa, exp_timestamp]):
            raise ValueError("JWT inválido. Faltam campos essenciais.")

        exp_datetime = datetime.fromtimestamp(exp_timestamp, tz=SAO_PAULO_TZ)
        encrypted_cookie = encrypt_data(cookie_string)
        
        conn = get_db_connection()
        try:
            with conn.cursor() as cur:
                query = """
                    INSERT INTO customer_sessoes_fgts 
                    (id_contabilidade, cnpj, nome_empresa, cookies_completos, expira_em, status, ultima_renovacao)
                    VALUES (%s, %s, %s, %s, %s, 'ativo', %s) 
                    ON CONFLICT (id_contabilidade, cnpj) DO UPDATE SET
                        nome_empresa = EXCLUDED.nome_empresa,
                        cookies_completos = EXCLUDED.cookies_completos,
                        expira_em = EXCLUDED.expira_em,
                        status = 'ativo',
                        ultima_renovacao = EXCLUDED.ultima_renovacao,
                        observacoes = NULL;
                """
                cur.execute(query, (id_contabilidade, cnpj, nome_empresa, 
                                encrypted_cookie, exp_datetime, datetime.now(SAO_PAULO_TZ)))
                conn.commit()
            return {"status": "sucesso", "cnpj": cnpj}
        finally:
            conn.close()
    except (ValueError, jwt.PyJWTError) as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        print(f"Erro inesperado no registro: {e}")
        raise HTTPException(status_code=500, detail="Ocorreu um erro interno no servidor.")
    
