from datetime import datetime


class _NotRequired:
    none = ""

    default = none


class _ContextMeasure:
    pts = "PTS"
    fgm = "FGM"
    fga = "FGA"
    fg_pct = "FG_PCT"
    fg3m = "FG3M"
    fg3a = "FG3A"
    fg3_pct = "FG3_PCT"
    pts_fb = "PTS_FB"
    pts_off_tov = "PTS_OFF_TOV"
    pts_2nd_chance = "PTS_2ND_CHANCE"

    default = pts


class _No:
    no = "N"

    default = no


class _YesNo(_No):
    yes = "Y"


class Active:
    all_player = "0"
    active_player = "1"

    default = all_player


class ActiveNullable(_NotRequired, Active):
    pass


class AheadBehind:
    ahead_or_behind = "Ahead or Behind"
    behind_or_tied = "Behind or Tied"
    ahead_or_tied = "Ahead or Tied"

    default = ahead_or_behind


class AheadBehindNullable(_NotRequired, AheadBehind):
    pass


class AllStar:
    all_player = "0"
    all_star = "1"

    default = all_player


class AllStarNullable(_NotRequired, AllStar):
    pass


class ClutchTime:
    last_5_minutes = "Last 5 Minutes"
    last_4_minutes = "Last 4 Minutes"
    last_3_minutes = "Last 3 Minutes"
    last_2_minutes = "Last 2 Minutes"
    last_1_minute = "Last 1 Minute"
    last_30_seconds = "Last 30 Seconds"
    last_10_seconds = "Last 10 Seconds"

    default = last_5_minutes


class ClutchTimeNullable(_NotRequired, ClutchTime):
    pass


class Conference:
    east = "East"
    west = "West"
    none = ""

    default = none


class ConferenceNullable(_NotRequired, Conference):
    pass


class ContextMeasureSimple(_ContextMeasure):
    pf = "PF"
    efg_pct = "EFG_PCT"
    ts_pct = "TS_PCT"


class ContextMeasureSimpleNullable(_NotRequired, ContextMeasureSimple):
    pass


class ContextMeasureDetailed(_ContextMeasure):
    ftm = "FTM"
    fta = "FTA"
    oreb = "OREB"
    dreb = "DREB"
    ast = "AST"
    fgm_ast = "FGM_AST"
    fg3_ast = "FG3_AST"
    stl = "STL"
    blk = "BLK"
    blka = "BLKA"
    tov = "TOV"
    poss_end_ft = "POSS_END_FT"
    pts_paint = "PTS_PAINT"
    reb = "REB"
    tm_fgm = "TM_FGM"
    tm_fga = "TM_FGA"
    tm_fg3m = "TM_FG3M"
    tm_fg3a = "TM_FG3A"
    tm_ftm = "TM_FTM"
    tm_fta = "TM_FTA"
    tm_oreb = "TM_OREB"
    tm_dreb = "TM_DREB"
    tm_reb = "TM_REB"
    tm_team_reb = "TM_TEAM_REB"
    tm_ast = "TM_AST"
    tm_stl = "TM_STL"
    tm_blk = "TM_BLK"
    tm_blka = "TM_BLKA"
    tm_tov = "TM_TOV"
    tm_team_tov = "TM_TEAM_TOV"
    tm_pf = "TM_PF"
    tm_pfd = "TM_PFD"
    tm_pts = "TM_PTS"
    tm_pts_paint = "TM_PTS_PAINT"
    tm_pts_fb = "TM_PTS_FB"
    tm_pts_off_tov = "TM_PTS_OFF_TOV"
    tm_pts_2nd_chance = "TM_PTS_2ND_CHANCE"
    tm_fgm_ast = "TM_FGM_AST"
    tm_fg3_ast = "TM_FG3_AST"
    tm_poss_end_ft = "TM_POSS_END_FT"
    opp_ftm = "OPP_FTM"
    opp_fta = "OPP_FTA"
    opp_oreb = "OPP_OREB"
    opp_dreb = "OPP_DREB"
    opp_reb = "OPP_REB"
    opp_team_reb = "OPP_TEAM_REB"
    opp_ast = "OPP_AST"
    opp_stl = "OPP_STL"
    opp_blk = "OPP_BLK"
    opp_blka = "OPP_BLKA"
    opp_tov = "OPP_TOV"
    opp_team_tov = "OPP_TEAM_TOV"
    opp_pf = "OPP_PF"
    opp_pfd = "OPP_PFD"
    opp_pts = "OPP_PTS"
    opp_pts_paint = "OPP_PTS_PAINT"
    opp_pts_fb = "OPP_PTS_FB"
    opp_pts_off_tov = "OPP_PTS_OFF_TOV"
    opp_pts_2nd_chance = "OPP_PTS_2ND_CHANCE"
    opp_fgm_ast = "OPP_FGM_AST"
    opp_fg3_ast = "OPP_FG3_AST"
    opp_poss_end_ft = "OPP_POSS_END_FT"


class DayOffset:
    def days(self, i):
        return str(int(i))

    default = "0"


class DefenseCategory:
    overall = "Overall"
    threes = "3 Pointers"
    twos = "2 Pointers"
    less_than_6ft = "Less Than 6Ft"
    less_than_10ft = "Less Than 10Ft"
    greater_than_15ft = "Greater Than 15Ft"

    default = overall


class DefenseCategoryNullable(_NotRequired, DefenseCategory):
    pass


class Direction:
    asc = "ASC"
    desc = "DESC"

    default = asc


class DistanceRange:
    range_5ft = "5ft Range"
    range_8ft = "8ft Range"
    by_zone = "By Zone"

    default = by_zone


class DivisionSimple:
    atlantic = "Atlantic"
    central = "Central"
    northwest = "Northwest"
    pacific = "Pacific"
    southeast = "Southeast"
    southwest = "Southwest"

    default = atlantic


class DivisionSimpleNullable(_NotRequired, DivisionSimple):
    pass


class Division:
    east = "East"
    west = "West"

    default = east


class DivisionNullable(_NotRequired, Division):
    pass


class EndRange:
    default = "0"


class EndRangeNullable(_NotRequired, EndRange):
    pass


class GameDate:
    def get_date_format(self, datetime):
        return str(datetime.date())

    def get_date(self, year, month, day):
        return str(datetime(year=year, month=month, day=day).date())

    default = str(datetime.now().date())


class GameScopeSimple:
    last_10 = "Last 10"
    yesterday = "Yesterday"

    default = last_10


class GameScopeSimpleNullable(_NotRequired, GameScopeSimple):
    pass


class GameScopeDetailed(GameScopeSimple):
    season = "Season"
    finals = "Finals"

    default = season


class GameSegment:
    first_half = "First Half"
    overtime = "Overtime"
    second_half = "Second Half"

    default = first_half


class GameSegmentNullable(_NotRequired, GameSegment):
    pass


class GroupQuantity:
    def players(self, i):
        return str(int(i))

    default = "5"


class Historical:
    season = "0"
    all_time = "1"

    default = season


class HistoricalNullable(_NotRequired, Historical):
    pass


class LastNGames:
    def games(self, i):
        return str(int(i))

    default = "0"


class LastNGamesNullable(_NotRequired, LastNGames):
    pass


class LeagueID:
    nba = "00"
    aba = "01"
    wnba = "10"
    summer_league = "15"
    g_league = "20"

    default = nba


class LeagueIDNullable(_NotRequired, LeagueID):
    # Override default to NBA since empty LeagueID causes issues with IST games
    # (e.g., returns 87 games instead of 82 for 2023-24 season)
    default = LeagueID.nba


class Location:
    home = "Home"
    road = "Road"

    default = home


class LocationNullable(_NotRequired, Location):
    pass


class MeasureTypeBase:
    base = "Base"

    default = base


class MeasureTypeSimple(MeasureTypeBase):
    opponent = "Opponent"


class MeasureTypePlayerGameLogs(MeasureTypeBase):
    advanced = "Advanced"
    misc = "Misc"
    scoring = "Scoring"
    usage = "Usage"


class MeasureTypeDetailed(MeasureTypeSimple, MeasureTypePlayerGameLogs):
    four_factors = "Four Factors"


class MeasureTypeDetailedDefense(MeasureTypeDetailed):
    defense = "Defense"


class Month:
    def month(self, i):
        return str(int(i))

    default = "0"


class MonthNullable(_NotRequired, Month):
    pass


class NumberOfGames:
    def games(self, i):
        return str(int(i))

    default = "2147483647"


class Outcome:
    win = "W"
    loss = "L"

    default = win


class OutcomeNullable(_NotRequired, Outcome):
    pass


class PaceAdjust(_YesNo):
    pass


class PaceAdjustNo(_No):
    pass


class PlusMinus(_YesNo):
    pass


class PlusMinusNo(_No):
    pass


class Period:
    all = "0"

    first = "1"
    second = "2"
    third = "3"
    fourth = "4"

    def quarter(self, i):
        return str(int(i))

    def overtime(self, i):
        return str(4 + int(i))

    default = all


class PeriodNullable(_NotRequired, Period):
    pass


class StartPeriod(Period):
    pass


class StartPeriodNullable(_NotRequired, StartPeriod):
    pass


class EndPeriod(Period):
    pass


class EndPeriodNullable(_NotRequired, EndPeriod):
    pass


class PerModeSimple:
    totals = "Totals"
    per_game = "PerGame"

    default = totals


class PerModeSimpleNullable(_NotRequired, PerModeSimple):
    pass


class PerMode36(PerModeSimple):
    per_36 = "Per36"


class PerMode48(PerModeSimple):
    per_48 = "Per48"


class PerModeTime(PerMode36, PerMode48):
    minutes_per = "MinutesPer"
    per_40 = "Per40"


class PerModeDetailed(PerModeTime):
    per_minute = "PerMinute"
    per_possession = "PerPossession"
    per_play = "PerPlay"
    per_100_possessions = "Per100Possessions"
    per_100_plays = "Per100Plays"


class PlayerExperience:
    rookie = "Rookie"
    sophomore = "Sophomore"
    veteran = "Veteran"

    default = rookie


class PlayerExperienceNullable(_NotRequired, PlayerExperience):
    pass


class PlayerOrTeam:
    player = "Player"
    team = "Team"

    default = team


class PlayerOrTeamAbbreviation:
    player = "P"
    team = "T"

    default = team


class PlayerPosition:
    forward = "Forward"
    center = "Center"
    guard = "Guard"

    default = forward


class PlayerPositionNullable(_NotRequired, PlayerPosition):
    pass


class PositionNullable(_NotRequired, PlayerPosition):
    pass


class PlayerPositionAbbreviation:
    forward = "F"
    center = "C"
    guard = "G"
    center_forward = "C-F"
    forward_center = "F-C"
    forward_guard = "F-G"
    guard_forward = "G-F"

    default = forward


class PlayerPositionAbbreviationNullable(_NotRequired, PlayerPositionAbbreviation):
    pass


class PlayerScope:
    all_players = "All Players"
    rookies = "Rookies"

    default = all_players


class TodaysPlayers(_YesNo):
    pass


class ActivePlayers(_YesNo):
    pass


class PlayType:
    transition = "Transition"
    isolation = "Isolation"
    pr_ball_handler = "PRBallHandler"
    pr_roll_man = "PRRollman"
    post_up = "Postup"
    spot_up = "Spotup"
    handoff = "Handoff"
    cut = "Cut"
    off_screen = "OffScreen"
    putbacks = "OffRebound"
    misc = "Misc"

    default = transition


class PlayTypeNullable(_NotRequired, PlayType):
    pass


class PointDiff:
    def points(self, i):
        return str(int(i))

    default = "5"


class PointDiffNullable(_NotRequired, PointDiff):
    pass


class PtMeasureType:
    speed_distance = "SpeedDistance"
    rebounding = "Rebounding"
    possessions = "Possessions"
    catch_shoot = "CatchShoot"
    pull_up_shot = "PullUpShot"
    defense = "Defense"
    drives = "Drives"
    passing = "Passing"
    elbowTouch = "ElbowTouch"
    postTouch = "PostTouch"
    paintTouch = "PaintTouch"
    efficiency = "Efficiency"

    default = speed_distance


class RangeType:
    default = "0"


class RangeTypeNullable(_NotRequired, RangeType):
    pass


class Rank(_YesNo):
    pass


class RankNo(_No):
    pass


class RunType:
    default = "each second"


class StartRange:
    default = "0"


class StartRangeNullable(_NotRequired, StartRange):
    pass


class Scope:
    rs = "RS"
    s = "S"
    rookies = "Rookies"

    default = s


class SeasonYear:
    current_datetime = datetime.now()
    current_season_year = current_datetime.year
    if current_datetime.month <= 9:
        current_season_year -= 1

    default = current_season_year


class WnbaSeasonYear:
    current_datetime = datetime.now()
    current_season_year = current_datetime.year

    default = current_season_year


class SeasonYearNullable(_NotRequired, SeasonYear):
    pass


class Season(SeasonYear):
    current_season_year = SeasonYear.current_season_year
    current_season = "{}-{}".format(
        current_season_year, str(current_season_year + 1)[2:]
    )

    # Get last Season
    previous_season = "{}-{}".format(
        current_season_year - 1, str(current_season_year)[2:]
    )

    default = current_season


class WnbaSeason(WnbaSeasonYear):
    current_season_year = WnbaSeasonYear.current_season_year

    current_season = "{}".format(current_season_year)
    previous_season = "{}".format(current_season_year - 1)

    default = current_season


class SeasonNullable(_NotRequired, Season):
    pass


class SeasonAll(Season):
    all = "ALL"


class SeasonAllNullable(_NotRequired, SeasonAll):
    pass


class SeasonAll_Time(Season):
    all_time = "All Time"


class SeasonAllTime(Season):
    alltime = "ALLTIME"


class SeasonID(SeasonYear):
    def get_season_id(self, season_year):
        return "2{}".format(season_year)

    current_season_year = SeasonYear.current_season_year
    current_season_year = "2{}".format(current_season_year)

    default = current_season_year


class SeasonType:
    regular = "Regular Season"
    preseason = "Pre Season"
    playin = "PlayIn"

    default = regular


class SeasonTypePlayoffs(SeasonType):
    playoffs = "Playoffs"


class SeasonTypeNullable(_NotRequired, SeasonTypePlayoffs):
    pass


class SeasonTypeAllStar(SeasonTypePlayoffs):
    all_star = "All Star"


class SeasonTypeAllStarNullable(_NotRequired, SeasonTypePlayoffs):
    pass


class SeasonSegment:
    post_all_star = "Post All-Star"
    pre_all_star = "Pre All-Star"

    default = post_all_star


class SeasonSegmentNullable(_NotRequired, SeasonSegment):
    pass


class Section:
    group = "group"
    wildcard = "wildcard"

    default = group


class ShotClockRange:
    def calculate_range(self, i):
        i = float(i)
        if i > 24 or i <= 0:
            return ""
        elif 22 < i <= 24:
            return "24-22"
        elif 18 < i <= 22:
            return "22-18 Very Early"
        elif 15 < i <= 18:
            return "18-15 Early"
        elif 7 < i <= 15:
            return "15-7 Average"
        elif 4 < i <= 7:
            return "7-4 Late"
        elif 0 < i <= 4:
            return "4-0 Very Late"

    range_22_24 = "24-22"
    range_18_22 = "22-18 Very Early"
    range_15_18 = "18-15 Early"
    range_7_15 = "15-7 Average"
    range_4_7 = "7-4 Late"
    range_0_4 = "4-0 Very Late"
    shot_clock_off = "ShotClock Off"

    default = shot_clock_off


class ShotClockRangeNullable(_NotRequired, ShotClockRange):
    pass


class Sorter:
    fgm = "FGM"
    fga = "FGA"
    fg_pct = "FG_PCT"
    fg3m = "FG3M"
    fg3a = "FG3A"
    fg3_pct = "FG3_PCT"
    ftm = "FTM"
    fta = "FTA"
    ft_pct = "FT_PCT"
    oreb = "OREB"
    dreb = "DREB"
    ast = "AST"
    stl = "STL"
    blk = "BLK"
    tov = "TOV"
    reb = "REB"
    pts = "PTS"
    date = "DATE"

    default = date


class StarterBench:
    starters = "Starters"
    bench = "Bench"

    default = starters


class StarterBenchNullable(_NotRequired, StarterBench):
    pass


class Stat:
    points = "PTS"
    rebounds = "REB"
    assists = "AST"
    field_goal_percent = "FG_PCT"
    free_throw_percent = "FT_PCT"
    threes_percent = "FG3_PCT"
    steals = "STL"
    blocks = "BLK"

    default = points


class StatCategory:
    points = "Points"
    rebounds = "Rebounds"
    assists = "Assists"
    defense = "Defense"
    clutch = "Clutch"
    playmaking = "Playmaking"
    efficiency = "Efficiency"
    fast_break = "Fast Break"
    scoring_breakdown = "Scoring Breakdown"

    default = points


class StatCategoryAbbreviation:
    pts = "PTS"
    fgm = "FGM"
    fga = "FGA"
    fg_pct = "FG_PCT"
    fg3m = "FG3M"
    fg3a = "FG3A"
    fg3_pct = "FG3_PCT"
    ftm = "FTM"
    fta = "FTA"
    oreb = "OREB"
    dreb = "DREB"
    ast = "AST"
    stl = "STL"
    blk = "BLK"
    tov = "TOV"
    reb = "REB"

    default = pts


class StatType:
    traditional = "Traditional"
    advanced = "Advanced"
    tracking = "Tracking"

    default = traditional


class TypeGrouping:
    offensive = "offensive"
    defensive = "defensive"

    default = offensive


class TypeGroupingNullable(_NotRequired, TypeGrouping):
    pass
