"""

    AUTHOR:

        Khushal P Soonderji

    DATE:

        Thursday, 28th Nov., 2024

    OBJECTIVE:

        To provide a way to retrieve dates of important events like financial-results, stock-splits, fund-raising, etc.
        from NSE's portal.

        NOTE: This method involves web scraping. It is good for proof-of-concept development, but it is recommended that
        more professional data-sources be used when the product starts becoming mature.

    REFERENCES:

        N/A

    DOWNLOADS:

        N/A

"""


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                                   IMPORT                                                      ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


# To make sibling directories accessible for imports:
import sys
sys.path.append(".")
sys.path.append("..")

# System-level activities:
import io

# My utils:
from utils_v2.string import json
from utils_v2.date_time import date_time

# NSE-related utils:
# from utils_v2.nse.base import AsyncNSEBase
from utils_v2.nse.models.behaviour.base import AsyncNSEBase
from utils_v2.nse.models.data.api_call import NSEApiResponse

# To make REST-ful API calls:
import httpx

# To work with date and time:
import datetime

# To work with datatypes:
from typing import Any, List

# For asynchronous activities:
import asyncio


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                           MACROS / ONE-TIME INIT                                              ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


# --- Nothing Yet


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                                VARIABLES                                                      ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


# --- Nothing Yet


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                                  FUNCTIONS                                                    ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


class NSECorporateEventCalendar(AsyncNSEBase):

    def __init__(
            self,
            http_client: httpx.AsyncClient,
            debug = True,
            debug_prefix = "NSE (CECal) | ",
            debug_only_errors = True
    ):

        # Pass on the initialization to the parent:
        super().__init__(
            base_url = r"https://www.nseindia.com/companies-listing/corporate-filings-event-calendar",
            data_url = r"https://www.nseindia.com/api/event-calendar",
            http_client = http_client,
            debug = debug,
            debug_prefix = debug_prefix,
            debug_only_errors = debug_only_errors
        )

    async def get_data(
            self,
            return_raw: bool = False,
    ) -> NSEApiResponse:

        """
        To get the data of the corporate event calendar.
        :param return_raw: Whether you want the raw JSON from NSE or you want it formatted.
        :return: The raw or formatted event calendar data in the 'data' field of the response model.
        """

        # Make the API call:
        api_response = await self.get()

        # If the API call was successful:
        if api_response.httpCode in [200]:
            api_response.success = True
            if return_raw: api_response.data = await api_response.get_json()
            else:
                try: api_response.data = self.format_data(
                    raw_json = await api_response.get_json(),
                    timestamp = date_time.get_current_utc_date_time(as_string = True),
                    raise_exception = True
                )
                except Exception as exception:
                    api_response.exception = exception
                    api_response.success = False

        # Done here:
        return api_response

    @staticmethod
    def format_data(
            raw_json: List[dict],
            timestamp: datetime.datetime = None,
            raise_exception: bool = False
    ) -> List[dict] | None:

        """
        We format the data here to be able to retrieve it properly later.
        :param raw_json: The raw data as scraped from NSE.
        :param timestamp: The timestamp at which the data was scraped. This shall be useful for data retrieval from the
            database, later.
        :param raise_exception: If set to True, any exception will be propagated. If set to False, any exception will be
            suppressed internally.
        :return: The formatted data if successful, else None.
        """

        # Can't do anything if the chain itself is null:
        if raw_json is None: return raw_json

        # Start by assuming failure:
        formatted_data = None

        # Ensure that we've got a proper timestamp:
        if timestamp is None: timestamp = date_time.get_current_utc_date_time(as_string = False)

        try:

            # Format the data:
            formatted_data = [
                {
                    "scrapeTs": timestamp,
                    "symbol": event["symbol"],
                    "company": event["company"],
                    "eventDate": date_time.to_timezone(
                        date_time.parse_date_time(
                            event["date"],
                            timezone = date_time.TIMEZONE_IST
                        ),
                        timezone = date_time.TIMEZONE_UTC
                    ),
                    "eventType": event["purpose"],
                    "brief": event["bm_desc"]
                } for event in raw_json
            ]

        # If something goes wrong:
        except Exception as exception:
            formatted_data = None
            if raise_exception: raise

        # Done here:
        return formatted_data


#   *****************************************************************************************************************
#  *****                                                                                                          ****
# ***                                               MAIN PROGRAM                                                    ***
#  *****                                                                                                          ****
#   *****************************************************************************************************************


if __name__ == "__main__":

    async def main():

        # Create an HTTP client:
        test_client = httpx.AsyncClient(
            limits = httpx.Limits(
                max_connections = 100,  # ............ Maximum number of connections allowed in the pool.
                max_keepalive_connections = 50,  # ... Maximum number of connections that can be kept alive.
            ),
            timeout = httpx.Timeout(
                pool = 120.0,  # .... Time to wait for a free connection from the pool.
                connect = 2.5,  # ... Time to wait for establishing a connection to the server.
                write = 10.0,  # .... Time to wait for sending data.
                read = 2.5  # ....... Time to wait for receiving data.
            )
        )

        # Create an instance of the scraper, and refresh its cookies:
        my_nse = NSECorporateEventCalendar(http_client = test_client)

        # Get and show the data:
        api_response = await my_nse.get_data(return_raw = False)
        print("SUMMARY:", api_response.to_markdown(), "\n---\n\n")
        if api_response.success: print("CORPORATE EVENT CALENDAR:", json.to_string(api_response.data, default = str))

    asyncio.run(main())
