import httpx
import re
import sys
from loguru import logger
from typing import Dict, Any, Optional

# Configure logger
logger.remove()
logger.add(sys.stderr, format="<green>{time:HH:mm:ss}</green> | <level>{level: <8}</level> | <level>{message}</level>")

class SigaClient:
    """
    Asynchronous client for interacting with the Activesoft Siga API.
    """
    BASE_URL = "https://siga02.activesoft.com.br"
    LOGIN_PAGE_URL = f"{BASE_URL}/login/"
    API_ALUNOS_URL = f"{BASE_URL}/api/v1/alunos/"
    API_RESPONSAVEL_URL = f"{BASE_URL}/api/v1/responsavel/"
    API_RESPONSAVEL_DETALHE_URL_TEMPLATE = f"{BASE_URL}/api/v1/responsavel/crud/{{}}/"
    API_DETALHE_URL_TEMPLATE = f"{BASE_URL}/api/v1/alunos/crud/{{}}/"
    API_MENSAGEM_SAIDA_URL = f"{BASE_URL}/api/v1/mensagem_caixa_saida/"

    def __init__(self, username, password, instituicao):
        self.username = username
        self.password = password
        self.instituicao = instituicao
        self.client = httpx.AsyncClient(follow_redirects=True, timeout=30.0)
        self.login_url = f"{self.LOGIN_PAGE_URL}?instituicao={instituicao}"
        self.csrf_token = None

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.client.aclose()

    async def _get_csrf_token(self):
        """
        Fetches the login page and extracts the CSRF token.
        """
        logger.info(f"Fetching login page for CSRF token: {self.login_url}")
        response = await self.client.get(self.login_url)
        response.raise_for_status()
        
        match = re.search(r'<input type="hidden" name="csrfmiddlewaretoken" value="([^"]+)"', response.text)
        if match:
            token = match.group(1)
            logger.success(f"CSRF Token found: {token[:15]}...")
            return token
        else:
            raise ValueError("CSRF token not found on the login page.")

    async def login(self):
        """
        Performs the login and initializes the authenticated session.
        """
        self.csrf_token = await self._get_csrf_token()
        
        payload = {
            "csrfmiddlewaretoken": self.csrf_token,
            "codigo": self.instituicao,
            "login": self.username,
            "senha": self.password
        }
        
        logger.info(f"Attempting to log in as {self.username}...")
        response = await self.client.post(self.login_url, data=payload, headers={"Referer": self.login_url})
        response.raise_for_status()
        
        auth_jwt = self.client.cookies.get("auth_jwt")
        if auth_jwt:
            logger.success("Login successful! Found auth_jwt cookie.")
            # Set default headers for subsequent API calls
            self.client.headers.update({
                "X-CSRFToken": self.csrf_token,
                "Referer": f"{self.BASE_URL}/alunos/"
            })
            return True
        else:
            logger.warning("Login might have failed. 'auth_jwt' cookie not found.")
            return False

    async def list_alunos(self, limit=10, offset=0, search="", pesquisa_qualquer_trecho=True, apenas_ativos=False):
        """
        Retrieves the list of students from the API.
        """
        params = {
            "limit": limit,
            "offset": offset,
            "search": search,
            "pesquisa_qualquer_trecho": str(pesquisa_qualquer_trecho).lower(),
            "apenas_ativos": str(apenas_ativos).lower()
        }
        
        logger.info(f"Listing alunos (limit={limit}, offset={offset})...")
        response = await self.client.get(self.API_ALUNOS_URL, params=params)
        response.raise_for_status()
        
        data = response.json()
        logger.success(f"Retrieved {len(data.get('results', []))} students (Total: {data.get('count')})")
        return data

    async def list_responsaveis(self, limit=21, offset=0, search="", pesquisa_qualquer_trecho=True, apenas_ativos=True):
        """
        Retrieves the list of responsible parties (guardians) from the API.
        """
        params = {
            "limit": limit,
            "offset": offset,
            "maximoPorPagina": limit,
            "search": search,
            "pesquisa_qualquer_trecho": str(pesquisa_qualquer_trecho).lower(),
            "apenas_ativos": str(apenas_ativos).lower()
        }
        
        logger.info(f"Listing responsaveis (limit={limit}, offset={offset})...")
        response = await self.client.get(self.API_RESPONSAVEL_URL, params=params)
        response.raise_for_status()
        
        data = response.json()
        logger.success(f"Retrieved {len(data.get('results', []))} responsible parties (Total: {data.get('count', 'N/A')})")
        return data

    async def get_responsavel_detail(self, responsavel_id):
        """
        Retrieves full details for a specific responsible party.
        """
        url = self.API_RESPONSAVEL_DETALHE_URL_TEMPLATE.format(responsavel_id)
        
        # Update Referer for this specific detail view
        detail_referer = f"{self.BASE_URL}/responsaveis/{responsavel_id}/detalhe"
        headers = {"Referer": detail_referer}
        
        logger.info(f"Fetching details for responsible party ID: {responsavel_id}")
        response = await self.client.get(url, headers=headers)
        response.raise_for_status()
        
        data = response.json()
        resp_data = data.get('responsavel', data)
        name = resp_data.get('nome', resp_data.get('nome_completo', 'Unknown'))
        
        logger.success(f"Detail found for: {name}")
        return data

    async def get_aluno_detail(self, aluno_id):
        """
        Retrieves full details for a specific student.
        """
        url = self.API_DETALHE_URL_TEMPLATE.format(aluno_id)
        
        # Update Referer for this specific detail view
        detail_referer = f"{self.BASE_URL}/alunos/{aluno_id}/detalhe/"
        headers = {"Referer": detail_referer}
        
        logger.info(f"Fetching details for student ID: {aluno_id}")
        response = await self.client.get(url, headers=headers)
        response.raise_for_status()
        
        data = response.json()
        student_data = data.get('aluno', data)
        name = student_data.get('nome', student_data.get('nome_completo', 'Unknown'))
        
        logger.success(f"Detail found for: {name}")
        return data

    async def send_message(self, student_id, destinatario_id, message_text, message_title="Aviso", destinatario_tipo="R", origem=2):
        """
        Sends a message through the ActiveSoft API.
        
        Args:
            student_id: The ID of the student.
            destinatario_id: The ID of the recipient (e.g., responsible party ID).
            message_text: The text of the message.
            message_title: The title of the message (default: "Aviso").
            destinatario_tipo: The type of recipient (default: "R").
            origem: The origin code (default: 2).
        """
        payload = [{
            "destinatario_tipo": destinatario_tipo,
            "destinatario_titulo": None,
            "destinatario": destinatario_id,
            "mensagem_texto": message_text,
            "mensagem_tipo": "M", # M for message?
            "mensagem_titulo": message_title,
            "origem": origem,
            "lista_anexos": None,
            "aluno": student_id
        }]
        
        logger.info(f"Sending message to recipient {destinatario_id} for student {student_id}...")
        
        headers = {
            "Content-Type": "application/json;charset=UTF-8",
            "Referer": f"{self.BASE_URL}/enviar_nova_mensagem/"
        }
        
        response = await self.client.post(self.API_MENSAGEM_SAIDA_URL, json=payload, headers=headers)
        response.raise_for_status()
        
        data = response.json()
        logger.success(f"Message sent successfully! Response: {data}")
        return data
