import json
import time
import requests
import os
from dotenv import load_dotenv
import jwt

load_dotenv()


class D2lAuthManager:
    def __init__(self, scopes=None,token_file_d2l='token.json',url_google_chat=None):
        self.server_auth_url = 'https://auth.brightspace.com/oauth2/auth'
        self.server_token_url = 'https://auth.brightspace.com/core/connect/token'
        self.redirect_uri = 'https://appspuros.fecaf.com.br/'
        self.token_file_d2l = token_file_d2l
        self.scopes = scopes
        self.url_google_chat = url_google_chat
    
    def _send_google_notification(self, text):
        """Google Chat incoming webhook using requests."""
        url = self.url_google_chat

        if not url or url.strip() == "":
            print(f"⚠️ [GOOGLE_NOTIFICACAO] URL vazia detectada. Notificação não enviada: {text[:100]}...")
            return False

        payload = {
            "text": text
        }
        headers = {
            "Content-Type": "application/json; charset=UTF-8"
        }
    
        response = requests.post(url, data=json.dumps(payload), headers=headers)
        if response.status_code == 200:
            print(f"✅ [GOOGLE_NOTIFICACAO] Notificação enviada com sucesso.")
            return True

    def _generate_token(self):
        url = 'https://auth.brightspace.com/core/connect/token'

        try:
            with open(self.token_file_d2l) as f:
                dados_token = json.loads(f.read())
        except FileNotFoundError:
            print(f"❌ [_generate_token] Arquivo {self.token_file_d2l} não encontrado para renovação")
            self._send_google_notification(f"❌ Arquivo {self.token_file_d2l} não encontrado para renovação")
            raise
        except json.JSONDecodeError as e:
            print(f"❌ [_generate_token] Erro ao ler JSON do token: {e}")
            self._send_google_notification(f"❌ Erro ao ler JSON do token: {e}")
            raise

        data = {
            'grant_type': 'refresh_token',
            'client_id': os.getenv('CLIENT_ID'),
            'client_secret': os.getenv('CLIENT_SECRET'),
            'refresh_token': dados_token['refresh_token']
        }
        try:
            print(f"🔄 [_generate_token] Renovando token...")
            response = requests.post(url=url, data=data)
            
            if response.status_code == 200:
                print(f"✅ [_generate_token] Token renovado com sucesso")
                response_data = response.json()
                dados_token = {
                    'nbf': str(int(time.time())),
                    'refresh_token': response_data.get('refresh_token', dados_token['refresh_token']),
                    'access_token': response_data['access_token']
                }
            else:
                print(f"❌ [_generate_token] Erro HTTP {response.status_code}: {response.text}")
                self._send_google_notification(f"❌ Erro HTTP {response.status_code}: {response.text}")
                raise ValueError(f"Erro ao renovar token: {response.text}")
                
        except requests.exceptions.RequestException as e:
            print(f"❌ [_generate_token] Erro de conexão: {e}")
            self._send_google_notification(f"❌ Erro de conexão: {e}")
            raise
        except KeyError as e:
            print(f"❌ [_generate_token] Campo ausente na resposta: {e}")
            print(f"❌ [_generate_token] Resposta recebida: {response.text if 'response' in locals() else 'N/A'}")
            self._send_google_notification(f"❌ Campo ausente na resposta: {e}")
            raise ValueError(f"Resposta inválida do servidor")
        except Exception as e:
            print(f"❌ [_generate_token] Erro inesperado: {e}")
            self._send_google_notification(f"❌ Erro inesperado: {e}")
            if 'response' in locals():
                raise ValueError(response.text)
            else:
                raise

        with open(self.token_file_d2l, 'w') as file:
            file.write(json.dumps(dados_token))

        return dados_token['access_token']

    def manage_token(self):
        try:
            if not os.path.exists(self.token_file_d2l):
                print(f"ℹ️ [manage_token] Arquivo {self.token_file_d2l} não encontrado, gerando novo token...")
                self._send_google_notification(f"❌ Arquivo {self.token_file_d2l} não encontrado, necessário autenticar novamente.")
                raise FileNotFoundError(f"Arquivo {self.token_file_d2l} não encontrado")

            with open(self.token_file_d2l) as f:
                dados_token = json.loads(f.read())
                token_str = dados_token['access_token']

            decoded = jwt.decode(token_str, options={"verify_signature": False})

            exp = decoded.get('exp')
            if exp is None:
                print(f"⚠️ [manage_token] Token sem campo 'exp', renovando...")
                self._send_google_notification(f"⚠️ Token sem campo 'exp', renovando...")
                return self._generate_token()

            agora = int(time.time())
            segundos = 300
            if exp - agora < segundos:
                print(f"ℹ️ [manage_token] Token expirando em breve ({exp - agora}s), renovando...")
                self._send_google_notification(f"🔄 Renovando token D2L, expirando em {exp - agora}s, renovando...")
                generate_token = self._generate_token()
                if generate_token != None:
                    self._send_google_notification(f"✅ Token D2L renovado com sucesso.")
                    return generate_token
            else:
                print(f"✅ [manage_token] Token válido até {exp} (restam {exp - agora}s)")
                self._send_google_notification(f"✅ Token válido até {exp} (restam {exp - agora}s)")
                return token_str

        except jwt.DecodeError as e:
            print(f"❌ [manage_token] Erro ao decodificar token: {e}, renovando...")
            self._send_google_notification(f"❌ Erro ao decodificar token: {e}, renovando...")
            return self._generate_token()
        except json.JSONDecodeError as e:
            print(f"❌ [manage_token] Erro ao ler JSON do token: {e}, renovando...")
            self._send_google_notification(f"❌ Erro ao ler JSON do token: {e}, renovando...")
            return self._generate_token()
        except KeyError as e:
            print(f"❌ [manage_token] Campo ausente no token JSON: {e}, renovando...")
            self._send_google_notification(f"❌ Campo ausente no token JSON: {e}, renovando...")
            return self._generate_token()
        except Exception as e:
            if isinstance(e, FileNotFoundError):
                raise
            print(f"❌ [manage_token] Erro inesperado: {e}, renovando...")
            self._send_google_notification(f"❌ Erro inesperado: {e}, renovando...")
            return self._generate_token()

    def authenticate(self):

        auth_data = {
            'response_type': 'code',
            'client_id': os.getenv('CLIENT_ID'),
            'client_secret': os.getenv('CLIENT_SECRET'),
            'redirect_uri': self.redirect_uri,
            'scope': ' '.join(self.scopes),
            'state': os.getenv('STATE')
        }

        auth_response = requests.get(url=self.server_auth_url, params=auth_data)

        print(auth_response.url)
        url = input('url: ')

        print('Processando a URL para extrair o código de autorização...')
        print(f'URL fornecida: {url}')
        if "code=" not in url:
            raise ValueError("❌ [authenticate] Parâmetro 'code' não encontrado na URL")
        code = url.split("code=")[-1].split("&")[0]
        print(f'Código obtido: {code}')

        token_data = {
            'grant_type': 'authorization_code',
            'code': code,
            'redirect_uri': self.redirect_uri,
            'client_id': os.getenv('CLIENT_ID'),
            'client_secret': os.getenv('CLIENT_SECRET'),
            'state': os.getenv('STATE')
        }

        token_response = requests.post(url=self.server_token_url, data=token_data)

        if token_response.status_code != 200:
            raise ValueError(f"❌ [authenticate] Erro ao obter token: {token_response.text}")

        token_json = token_response.json()
        token_data = {
            'nbf': str(int(time.time())),
            'refresh_token': token_json['refresh_token'],
            'access_token': token_json['access_token']
        }

        with open(self.token_file_d2l, 'w') as file:
            file.write(json.dumps(token_data))
        print(f"✅ [authenticate] Token salvo em {self.token_file_d2l}")

    def get_headers(self):
        """Retorna headers de autenticação com token"""
        return {'Authorization': 'Bearer ' + self.manage_token()}