import os
import platform
from enum import Enum
from pathlib import Path
from typing import Any, Literal

import matplotlib.pyplot as plt
import numpy as np
from matplotlib import rcParams
from matplotlib.axes import Axes
from matplotlib.figure import Figure
from numpy.typing import ArrayLike, NDArray


class Tableau20(str, Enum):
    blue = "#1F77B4"
    red = "#D62728"
    green = "#2CA02C"
    orange = "#FF7F0E"
    purple = "#9467BD"
    brown = "#8C564B"
    pink = "#E377C2"
    grey = "#7F7F7F"
    yellow = "#BCBD22"
    turquoise = "#17BECF"
    lightblue = "#AEC7E8"
    lightred = "#FF9896"
    lightorange = "#FFBB78"
    lightgreen = "#98DF8A"
    lightpurple = "#C5B0D5"
    lightbrown = "#C49C94"
    lightpink = "#F7B6D2"
    lightgrey = "#C7C7C7"
    lightyellow = "#DBDB8D"
    lightturquoise = "#9EDAE5"


DEFAULT_STYLE = {
    # Fonts and sizes
    "font.size": 14,
    "axes.titlesize": 16,
    "axes.titlepad": 10,
    "axes.labelsize": 14,
    "legend.fontsize": 12,
    "xtick.labelsize": 12,
    "ytick.labelsize": 12,
    # Axes properties
    "axes.linewidth": 1.5,
    "axes.edgecolor": "black",
    # Ticks
    "xtick.direction": "in",
    "ytick.direction": "in",
    "xtick.major.width": 1.2,
    "ytick.major.width": 1.2,
    "xtick.minor.width": 0.9,
    "ytick.minor.width": 0.9,
    "xtick.major.size": 6,
    "ytick.major.size": 6,
    "xtick.minor.size": 4,
    "ytick.minor.size": 4,
    "xtick.major.pad": 8,
    "ytick.major.pad": 8,
    # Enabling ticks on all sides
    "axes.spines.top": True,
    "axes.spines.right": True,
    "xtick.top": True,
    "ytick.right": True,
    "xtick.minor.top": True,
    "ytick.minor.right": True,
    # Subplot adjustments
    # "figure.subplot.left": 0.14,       # Default left margin
    # "figure.subplot.right": 0.95,    # Default right margin
    # "figure.subplot.bottom": 0.14,    # Default bottom margin
    # "figure.subplot.top": 0.9,       # Default top margin
    # "figure.subplot.wspace": 0.2,    # Default width space
    # "figure.subplot.hspace": 0.2,    # Default height space
    # "figure.constrained_layout.use": True,
    "figure.autolayout": True,
    # Grid
    # "axes.grid": True,               # Enable grid
    # "axes.facecolor": "#f0f0f0",     # Light grey background
    # "axes.grid.axis": "both",        # Grid for both axes
    # "axes.grid.which": "major",      # Major grid lines
    # "grid.color": "white",           # Gridline color
    # "grid.linestyle": "-",           # Solid gridlines
    # "grid.linewidth": 1,             # Gridline width
    # Lines and markers
    "lines.linewidth": 2,  # Line width
    "lines.markersize": 8,  # Marker size
    # Figure properties
    "savefig.dpi": 300,
    "savefig.bbox": "tight",
    "figure.figsize": (6, 4),
    # Disable frame on legend
    "legend.frameon": True,
    # Default color cycle
    # "axes.prop_cycle": rcParams['axes.prop_cycle'],
    # Additional spacing
    "axes.labelpad": 6,
}


def get_config_dir() -> Path:
    """
    Returns the default directory for configuration files based on the operating system.

    For Linux: ~/.config/<application_name>
    For macOS: ~/Library/Application Support/<application_name>
    For Windows: %APPDATA%\\<application_name>

    Returns
    -------
    config_dir: Path
        The default configuration directory for the operating system.
    """
    system = platform.system()

    if system == "Linux":
        config_dir = Path.home() / ".config"
    elif system == "Darwin":  # macOS
        config_dir = Path.home() / "Library" / "Application Support"
    elif system == "Windows":
        config_dir = Path(
            os.environ.get("APPDATA", Path.home() / "AppData" / "Roaming")
        )
    else:
        raise NotImplementedError(f"Unsupported operating system: {system}")

    return config_dir


def load_style() -> None:
    """
    Loads a style sheet for matplotlib figures from a user-created
    config file SYSTEM_CONFIG_DIR/boss/boss.mplstyle if it exists, otherwise
    fallsback to a default style.
    """
    config_dir = get_config_dir()
    style_path = config_dir / "boss" / "boss.mplstyle"
    if style_path.exists():
        style = style_path
    else:
        style = DEFAULT_STYLE
    plt.style.use(style)
