# Helper functions for FINRA API
import datetime
from typing import List

import requests


def get_finra_weeks(tier: str = "T1", is_ats: bool = True):
    """Fetches the available weeks from FINRA that can be used."""
    request_header = {"Accept": "application/json", "Content-Type": "application/json"}

    request_data = {
        "compareFilters": [
            {
                "compareType": "EQUAL",
                "fieldName": "summaryTypeCode",
                "fieldValue": "ATS_W_SMBL" if is_ats else "OTC_W_SMBL",
            },
            {
                "compareType": "EQUAL",
                "fieldName": "tierIdentifier",
                "fieldValue": tier,
            },
        ],
        "delimiter": "|",
        "fields": ["weekStartDate"],
        "limit": 52,
        "quoteValues": False,
        "sortFields": ["-weekStartDate"],
    }

    response = requests.post(
        "https://api.finra.org/data/group/otcMarket/name/weeklyDownloadDetails",
        headers=request_header,
        json=request_data,
        timeout=3,
    )

    return response.json() if response.status_code == 200 else []


def get_finra_data(symbol, week_start, tier: str = "T1", is_ats: bool = True):
    req_hdr = {
        "Accept": "application/json",
        "Content-Type": "application/json",
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ",
    }

    filters = [
        {
            "compareType": "EQUAL",
            "fieldName": "weekStartDate",
            "fieldValue": week_start,
        },
        {"compareType": "EQUAL", "fieldName": "tierIdentifier", "fieldValue": tier},
        {
            "compareType": "EQUAL",
            "description": "",
            "fieldName": "summaryTypeCode",
            "fieldValue": "ATS_W_SMBL" if is_ats else "OTC_W_SMBL",
        },
    ]

    if symbol:
        filters.append(
            {
                "compareType": "EQUAL",
                "fieldName": "issueSymbolIdentifier",
                "fieldValue": symbol,
            }
        )

    req_data = {
        "compareFilters": filters,
        "delimiter": "|",
        "fields": [
            "issueSymbolIdentifier",
            "totalWeeklyShareQuantity",
            "totalWeeklyTradeCount",
            "lastUpdateDate",
        ],
        "limit": 5000,
        "quoteValues": False,
        "sortFields": ["totalWeeklyShareQuantity"],
    }
    response = requests.post(
        "https://api.finra.org/data/group/otcMarket/name/weeklySummary",
        headers=req_hdr,
        json=req_data,
        timeout=2,
    )
    return response


def get_full_data(symbol, tier: str = "T1", is_ats: bool = True):
    weeks = [week["weekStartDate"] for week in get_finra_weeks(tier, is_ats)]

    data = []
    for week in weeks:
        response = get_finra_data(symbol, week, tier, is_ats)
        r_json = response.json()
        if response.status_code == 200 and r_json:
            data.append(response.json()[0])

    return data


def get_adjusted_date(year, month, day):
    # Get the date
    date = datetime.date(year, month, day)

    # If the date is a Saturday, subtract one day
    if date.weekday() == 5:
        date -= datetime.timedelta(days=1)
    # If the date is a Sunday, subtract two days
    elif date.weekday() == 6:
        date -= datetime.timedelta(days=2)

    return date


def get_short_interest_dates() -> List[str]:
    """
    Get a list of dates for which the short interest data is available.  It is reported on the 15th and the
    last day of each month,but if the date falls on a weekend, the date is adjusted to the closest friday.
    """

    def get_adjusted_date(year, month, day):
        """If the date falls on a weekend, find the closest date"""
        # Get the date
        date = datetime.date(year, month, day)

        # If the date is a Saturday, subtract one day
        if date.weekday() == 5:
            date -= datetime.timedelta(days=1)
        # If the date is a Sunday, subtract two days
        elif date.weekday() == 6:
            date -= datetime.timedelta(days=2)

        return date

    start_year = 2021
    today = datetime.date.today()  # Get today's date
    end_year = today.year
    dates_list = []

    for yr in range(start_year, end_year + 1):
        start_month = 7 if yr == start_year else 1
        end_month = 12 if yr < today.year else today.month - 1
        for month in range(start_month, end_month + 1):  # Start from July for 2021
            # Date for the 15th of the month
            date_15 = get_adjusted_date(yr, month, 15)
            dates_list.append(date_15.strftime("%Y%m%d"))

            # Date for the last day of the month
            if month == 2:  # February
                last_day = (
                    29 if (yr % 4 == 0 and yr % 100 != 0) or (yr % 400 == 0) else 28
                )
            elif month in [4, 6, 9, 11]:  # Months with 30 days
                last_day = 30
            else:  # Months with 31 days
                last_day = 31

            last_date = get_adjusted_date(yr, month, last_day)
            dates_list.append(last_date.strftime("%Y%m%d"))

    # Manually replace '20220415' with '20220414' due to holiday
    if "20220415" in dates_list:
        index = dates_list.index("20220415")
        dates_list[index] = "20220414"

    return dates_list
