import os
from datetime import datetime
from typing import Optional, List
from abc import abstractmethod
import csv
import psycopg2

import alpaca_trade_api as tradeapi

from wsbtrading.instrumentation import Alpaca as iAlpaca


class CSV:
    @abstractmethod
    def writerow(self, row: List[str]) -> None:
        pass

    @abstractmethod
    def writerows(self, rows: List[List[str]]) -> None:
        pass

    @abstractmethod
    def dialect(self) -> csv.Dialect:
        pass


def alpaca_rest_api_conn(trading_type: str):
    """Creates the initial connection to Alpaca API.

    Args:
        trading_type: denotes live versus paper trading

    Returns:
        an API connection to Alpaca

    Note:
        this may create many files on your computer

    **Example**

    .. code-block:: python

        from wsbtrading.data_io import data_io
        alpaca_api = data_io.alpaca_rest_api_conn(trading_type='paper_trading')
    """
    api_key = iAlpaca.api_key
    secret_key = iAlpaca.secret_key
    base_url = iAlpaca.api_call[trading_type]['base_url']

    return tradeapi.REST(api_key, secret_key, base_url=base_url)


def postgres_conn(database: str = 'wsb_trading_db',
            user: str = 'brian',
            password: str = '',
            host: str = '127.0.0.1',
            port: str = '5432'):
    """Creates the initial connection to Postgres.

    Args:
        database: denotes live versus paper trading
        user: the user to sign in as
        password: the password to sign in with
        host: the host URL
        port: the port number

    Returns:
        a Postgres connection

    **Example**

    .. code-block:: python

        from wsbtrading.data_io import data_io
        postgres_conn = data_io.postgres_conn()
    """
    conn = psycopg2.connect(database=database, user=user, password=password, host=host, port=port)
    cur = conn.cursor()

    return conn, cur


def generate_path_to_write(environment: str,
                           granularity: str,
                           dataset_name: str,
                           root_path: str = '/group/wsbtrading',
                           timestamp: Optional[str] = None):
    """Generates an HDFS path from the inputs.
    The output path is of the form ``/ROOT_PATH/ENVIRONMENT/GRANULARITY/DATASET_NAME/TIMESTAMP``

    Args:
        environment: possible values are 'dev' or 'prod'
        granularity: possible values are 'stream', 'minute', 'daily', 'weekly', 'monthly'
        dataset_name: the name of the dataset, with no spaces e.g. stock_ticker_metadata
        root_path: the root for your dataset path, e.g. ``/user/your_user`` or ``/group/wsbtrading``.
        Defaults to ``/group/wsbtrading``.
        experiment_id: the unique identifer for the experiment
        timestamp: the timestamp in UTC when the job ran, autogenerated. Can be overridden e.g. if user wants to
                   pass in some id like 'v1' or 'run10' or 'run_with_fixes'.

    Returns:
        The path to be written to

    **Example**
    .. code-block:: python

        from phobos import data_io
        data_io.generate_path_to_write(
            environment='prod',
            granularity='daily',
            dataset_name='stock_ticker_metadata'
        )
        # /group/wsbtrading/prod/aggregate/stock_ticker_metadata/file1.parquet...file2.parquet
    """
    supported_environments = ['dev', 'prod']
    supported_granularities = ['stream', 'minute', 'daily', 'weekly', 'monthly']

    if environment not in supported_environments or granularity not in supported_granularities:
        raise ValueError('Unsupported environment or granularity.')

    dataset_name = dataset_name.replace(' ', '_').lower()
    timestamp = timestamp or datetime.utcnow().strftime('%Y-%m-%d_%H-%M-%S')

    return os.path.join(root_path, environment, granularity, dataset_name, timestamp)

# https://docs.databricks.com/spark/latest/spark-sql/spark-pandas.html
# Enable Arrow-based columnar data transfers
# spark.conf.set("spark.sql.execution.arrow.pyspark.enabled", "true")
#
# # Generate a pandas DataFrame
# pdf = pd.DataFrame(np.random.rand(100, 3))
#
# # Create a Spark DataFrame from a pandas DataFrame using Arrow
# df = spark.createDataFrame(pdf)
#
# # Convert the Spark DataFrame back to a pandas DataFrame using Arrow
# result_pdf = df.select("*").toPandas()

# import config
# import websocket
# import json
# import requests

# def on_open(ws):
#     print("opened")
#     auth_data = {
#         "action": "authenticate",
#         "data": {"key_id": config.API_KEY, "secret_key": config.SECRET_KEY}
#     }
#
#     ws.send(json.dumps(auth_data))
#
#     listen_message = {"action": "listen", "data": {"streams": ["AM.TSLA"]}}
#
#     ws.send(json.dumps(listen_message))
#
#
# def on_message(ws, message):
#     print("received a message")
#     print(message)
#
#
# def on_close(ws):
#     print("closed connection")
#
#
# socket = "wss://data.alpaca.markets/stream"
#
#
# ws = websocket.WebSocketApp(socket, on_open=on_open, on_message=on_message, on_close=on_close)
# ws.run_forever()
