import os
import logging
import yaml
from fastapi import HTTPException, status
from supabase import create_client, Client, ClientOptions

from ..constants import PARAMETERS_DIR
from ..configuration.environment import Environment

# Silence the supabase logger
logging.getLogger("httpx").setLevel(logging.CRITICAL)
logging.getLogger("hpack").setLevel(logging.CRITICAL)
logging.getLogger("httpcore").setLevel(logging.CRITICAL)


class SupabaseClient:

    logger = logging.getLogger(__name__)

    def __init__(self):

        self.SUPABASE_URL = Environment.supabase_url
        self.SUPABASE_ADMIN_KEY = Environment.supabase_admin_key
        self.SUPABASE_TEST_USER_ID = Environment.supabase_test_user_id

        self.supabase = create_client(
            self.SUPABASE_URL, 
            self.SUPABASE_ADMIN_KEY, 
            options=ClientOptions(schema='public')
        )
        self.logger.info('Supabase client initialized.')


    def check_balance(self, user_id: str) -> bool:
        """
        Checks if the user has enough 'credit' for generating a new trip.

        Args:
            user_id (str): The ID of the current user.

        Returns:
            bool: True if the balance is positive, False otherwise.
        """
        try:
            # Query the public.credits table to get the user's credits
            response = (
                self.supabase.table("credits")
                .select('*')
                .eq('id', user_id)
                .single()
                .execute()
            )

        except Exception as e:
            if e.code == '22P02' :
                self.logger.error(f"Failed querying credits : {str(e)}")
                raise SyntaxError(f"Failed querying credits : {str(e)}") from e
            if e.code == 'PGRST116' :
                self.logger.error(f"User not found : {str(e)}")
                raise ValueError(f"User not found : {str(e)}") from e
            else :
                self.logger.error(f"An unexpected error occured while checking user balance : {str(e)}")
                raise Exception(f"An unexpected error occured while checking user balance : {str(e)}") from e

        # Proceed to check the user's credit balance
        credits = response.data['credit_amount']
        self.logger.debug(f'Credits of user {user_id}: {credits}')

        if credits > 0:
            self.logger.info(f'Credit balance is positive for user {user_id}. Proceeding with trip generation.')
            return True

        self.logger.warning(f'Insufficient balance for user {user_id}. Trip generation cannot proceed.')
        return False


    def decrement_credit_balance(self, user_id: str, amount: int=1) -> bool:
        """
        Decrements the user's credit balance by 1.

        Args:
            user_id (str): The ID of the current user.
        """
        try:
            # Query the public.credits table to get the user's current credits
            response = (
                self.supabase.table("credits")
                .select('*')
                .eq('id', user_id)
                .single()
                .execute()
            )
        except Exception as e:
            if e.code == '22P02' :
                self.logger.error(f"Failed decrementing credits : {str(e)}")
                raise SyntaxError(f"Failed decrementing credits : {str(e)}") from e
            if e.code == 'PGRST116' :
                self.logger.error(f"User not found : {str(e)}")
                raise ValueError(f"User not found : {str(e)}") from e
            else :
                self.logger.error(f"An unexpected error occured while decrementing user balance : {str(e)}")
                raise Exception(f"An unexpected error occured while decrementing user balance : {str(e)}") from e


        current_credits = response.data['credit_amount']
        updated_credits = current_credits - amount

        # Update the user's credits in the table
        update_response = (
            self.supabase.table('credits')
            .update({'credit_amount': updated_credits})
            .eq('id', user_id)
            .execute()
        )

        # Check if the update was successful
        if update_response.data:
            self.logger.debug(f'Credit balance successfully decremented.')
            return True
        else:
            raise Exception("Error decrementing credit balance.")


    def increment_credit_balance(self, user_id: str, amount: int=1) -> bool:
        """
        Increments the user's credit balance by 1.

        Args:
            user_id (str): The ID of the current user.
        """
        try:
            # Query the public.credits table to get the user's current credits
            response = (
                self.supabase.table("credits")
                .select('*')
                .eq('id', user_id)
                .single()
                .execute()
            )
        except Exception as e:
            if e.code == '22P02' :
                self.logger.error(f"Failed incrementing credits : {str(e)}")
                raise SyntaxError(f"Failed incrementing credits : {str(e)}") from e
            if e.code == 'PGRST116' :
                self.logger.error(f"User not found : {str(e)}")
                raise ValueError(f"User not found : {str(e)}") from e
            else :
                self.logger.error(f"An unexpected error occured while incrementing user balance : {str(e)}")
                raise Exception(f"An unexpected error occured while incrementing user balance : {str(e)}") from e


        current_credits = response.data['credit_amount']
        updated_credits = current_credits + amount

        # Update the user's credits in the table
        update_response = (
            self.supabase.table('credits')
            .update({'credit_amount': updated_credits})
            .eq('id', user_id)
            .execute()
        )

        # Check if the update was successful
        if update_response.data:
            self.logger.debug(f'Credit balance successfully incremented.')
            return True
        else:
            raise Exception("Error incrementing credit balance.")
