from fastapi import Request, HTTPException
from fastapi.responses import RedirectResponse, JSONResponse
from fastapi.templating import Jinja2Templates
from psycopg2.extras import DictCursor
from typing import List, Tuple
import jwt
from utils import get_db_connection, to_sao_paulo_time
from bootstrap import register_session_logic, decrypt_data
from pytz import timezone
from datetime import datetime
from services.encryption import EncryptionService
from models.panel import (
    Request,
    Response,
)

SAO_PAULO_TZ = timezone('America/Sao_Paulo')

templates = Jinja2Templates(directory="templates")
templates.env.filters['to_sao_paulo_time'] = to_sao_paulo_time


class PanelController:
    
    @staticmethod
    def flash(request: Request, message: str, category: str = "success"):
        """Adiciona uma mensagem flash à sessão."""
        if "_messages" not in request.session:
            request.session["_messages"] = []
        request.session["_messages"].append((category, message))

    @staticmethod
    def get_flashed_messages(request: Request) -> List[Tuple[str, str]]:
        """Retorna e remove as mensagens flash da sessão."""
        return request.session.pop("_messages") if "_messages" in request.session else []

    @staticmethod
    def get_all_sessions(request: Request):
        """Retorna todas as sessões ordenadas por data de criação."""
        conn = get_db_connection()
        try:
            with conn.cursor(cursor_factory=DictCursor) as cur:
                cur.execute("SELECT * FROM companies ORDER BY created_at DESC;")
                sessions = cur.fetchall()
                return templates.TemplateResponse("dashboard.html", {"request": request, "sessions": sessions})
        finally:
            conn.close()

    def store(self, request: Request, cookie: str):
        try:
            fgtsd_token_str = next((s.split('=')[1] for s in cookie.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")
            name = decoded_token.get("cnpj_nome")
            exp_timestamp = decoded_token.get("exp")

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

            if not isinstance(cnpj, str):
                raise ValueError("CNPJ deve ser uma string válida.")

            if not isinstance(exp_timestamp, (int, float)):
                raise ValueError("Timestamp de expiração deve ser um número válido.")

            exp_datetime = datetime.fromtimestamp(exp_timestamp, tz=SAO_PAULO_TZ)
            encrypted_cookie = EncryptionService.encrypt_data(cookie)
            
            conn = get_db_connection()
            try:
                with conn.cursor() as cur:
                    query = """
                        INSERT INTO companies (cnpj, name, cookie, expires_on, status, updated_at)
                        VALUES (%s, %s, %s, %s, 'active', %s) ON CONFLICT (cnpj) DO UPDATE SET
                            name = EXCLUDED.name, cookie = EXCLUDED.cookie,
                            expires_on = EXCLUDED.expires_on, status = 'active', updated_at = EXCLUDED.updated_at, details = NULL;
                    """
                    cur.execute(query, (cnpj, name, encrypted_cookie, exp_datetime, datetime.now(SAO_PAULO_TZ)))
                    conn.commit()
                    self.flash(request, "Sessão registrada/atualizada com sucesso!", "success")
                    return RedirectResponse(url="/panel", status_code=303)
            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 delete_session(self, request: Request, cnpj: str) -> RedirectResponse:
        """Remove uma sessão pelo CNPJ."""
        conn = get_db_connection()
        try:
            with conn.cursor() as cur:
                cur.execute("DELETE FROM companies WHERE cnpj = %s;", (cnpj,))
                conn.commit()
                
                if cur.rowcount > 0:
                    self.flash(request, f"Sessão do CNPJ {cnpj} removida com sucesso.", "success")
                else:
                    self.flash(request, f"Nenhuma sessão encontrada para o CNPJ {cnpj}.", "warning")
        except Exception as e:
            self.flash(request, f"Erro ao remover sessão: {e}", "danger")
        finally:
            conn.close()
        
        return RedirectResponse(url="/panel", status_code=303)



    def get_decrypted_cookie(self, cnpj: str) -> JSONResponse:
        """Busca um cookie pelo CNPJ, descriptografa e retorna como JSON."""
        conn = get_db_connection()
        try:
            with conn.cursor(cursor_factory=DictCursor) as cur:
                cur.execute("SELECT cookie FROM companies WHERE cnpj = %s;", (cnpj,))
                session_data = cur.fetchone()
            
            if not session_data:
                return JSONResponse(content={"error": "CNPJ não encontrado"}, status_code=404)

            decrypted_cookie = decrypt_data(session_data['cookie'])
            return JSONResponse(content={"decrypted_cookie": decrypted_cookie})

        except Exception as e:
            return JSONResponse(content={"error": str(e)}, status_code=500)
        finally:
            conn.close()

templates.env.globals['get_flashed_messages'] = PanelController.get_flashed_messages