import os
import webbrowser
from dotenv import load_dotenv
from fyers_api import fyersModel, accessToken
from loguru import logger

class FyersBroker:
    """
    Handles all interactions with the Fyers API.
    """
    def __init__(self, settings: dict):
        """
        Initializes the FyersBroker.

        Args:
            settings (dict): Application settings containing API credentials.
        """
        load_dotenv(dotenv_path=settings['credentials_path'])
        self.client_id = os.getenv('FYERS_CLIENT_ID')
        self.secret_key = os.getenv('FYERS_SECRET_KEY')
        self.redirect_uri = os.getenv('FYERS_REDIRECT_URI')
        self.access_token_path = settings['access_token_path']

        self.fyers = None
        self.access_token = self._load_access_token()

        if not self.access_token:
            self._generate_new_access_token()
        
        self._initialize_fyers_model()

    def _load_access_token(self) -> str | None:
        """Loads access token from the specified file."""
        try:
            if os.path.exists(self.access_token_path):
                with open(self.access_token_path, 'r') as f:
                    return f.read().strip()
            return None
        except Exception as e:
            logger.error(f"Error loading access token: {e}")
            return None

    def _save_access_token(self, token: str):
        """Saves access token to the specified file."""
        try:
            with open(self.access_token_path, 'w') as f:
                f.write(token)
            logger.info("Access token saved successfully.")
        except Exception as e:
            logger.error(f"Error saving access token: {e}")

    def _generate_new_access_token(self):
        """Generates a new access token using the auth code flow."""
        session = accessToken.SessionModel(
            client_id=self.client_id,
            secret_key=self.secret_key,
            redirect_uri=self.redirect_uri,
            response_type='code',
            grant_type='authorization_code'
        )

        try:
            response = session.generate_authcode()
            logger.info(f"Auth code generation response: {response}")
            print(f"Login URL: {response}")
            webbrowser.open(response)
            
            auth_code = input("Enter the auth code from the redirected URL: ")
            session.set_token(auth_code)
            
            access_token_response = session.generate_token()
            self.access_token = access_token_response['access_token']
            self._save_access_token(self.access_token)
            logger.info("New access token generated and saved.")

        except Exception as e:
            logger.error(f"Error generating new access token: {e}")
            self.access_token = None

    def _initialize_fyers_model(self):
        """Initializes the FyersModel with the access token."""
        if self.access_token:
            try:
                self.fyers = fyersModel.FyersModel(
                    client_id=self.client_id,
                    is_async=True,
                    token=self.access_token,
                    log_path=os.path.join(os.path.dirname(__file__), '..' , 'logs')
                )
                logger.info("FyersModel initialized successfully.")
            except Exception as e:
                logger.error(f"Error initializing FyersModel: {e}")
                self.fyers = None
        else:
            logger.warning("FyersModel could not be initialized. Access token is missing.")

    async def get_profile(self):
        """Fetches user profile details."""
        if not self.fyers:
            return {"error": "FyersModel not initialized."}
        try:
            response = await self.fyers.get_profile()
            if response['s'] == 'ok':
                return response['data']
            else:
                logger.error(f"Error fetching profile: {response['message']}")
                return {"error": response['message']}
        except Exception as e:
            logger.error(f"Exception fetching profile: {e}")
            return {"error": str(e)}

    async def get_funds(self):
        """Fetches user funds details."""
        if not self.fyers:
            return {"error": "FyersModel not initialized."}
        try:
            response = await self.fyers.get_funds()
            if response['s'] == 'ok':
                return response['fund_limit']
            else:
                logger.error(f"Error fetching funds: {response['message']}")
                return {"error": response['message']}
        except Exception as e:
            logger.error(f"Exception fetching funds: {e}")
            return {"error": str(e)}