"""Generator of samples of stereographic projection."""

import random
from datetime import datetime, timedelta
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np

from astrageek.catalogs.hip import Catalog, CatalogConstraints
from astrageek.catalogs.planets import PlanetCatalog
from astrageek.helpers.pdf_helpers.figure2pdf import save_figure_skychart
from astrageek.projections.stereographic import (
    ConstellationConfig,
    StereoProjConfig,
    StereoProjector,
)


def get_teacher_cfg(
    time: datetime,
    latitude: float,
    longitude: float,
) -> StereoProjConfig:
    """Get configuration for teacher mode.

    :param time: observation date and time
    :type time: datetime
    :param latitude: observation latitude
    :type latitude: float
    :param longitude: observation latitude
    :type longitude: float
    :return: Configuration for teacher mode
    :rtype: StereoProjConfig
    """

    return StereoProjConfig(
        add_ecliptic=True,
        add_equator=True,
        add_galactic_equator=True,
        add_planets=True,
        add_ticks=True,
        add_horizontal_grid=False,
        add_equatorial_grid=True,
        grid_theta_step=10.0,
        grid_phi_step=45.0,
        random_origin=True,
        local_time=time,
        latitude=latitude,
        longitude=longitude,
        add_constellations=True,  # Отрисовка линий созвездий
        add_constellations_names=True,  # Отрисовка названий созвездий
        add_zenith=True,
        add_poles=True,
    )


def get_student_cfg(
    time: datetime,
    latitude: float,
    longitude: float,
    add_planets: bool,
) -> StereoProjConfig:
    """Get configuration for teacher mode.

    :param time: observation date and time
    :type time: datetime
    :param latitude: observation latitude
    :type latitude: float
    :param longitude: observation latitude
    :type longitude: float
    :return: Configuration for student mode
    :rtype: StereoProjConfig
    """

    return StereoProjConfig(
        add_ecliptic=False,
        add_equator=False,
        add_galactic_equator=False,
        add_planets=add_planets,
        add_ticks=False,
        add_horizontal_grid=False,
        add_equatorial_grid=False,
        grid_theta_step=10.0,
        grid_phi_step=45.0,
        random_origin=True,
        local_time=time,
        latitude=latitude,
        longitude=longitude,
        add_zenith=False,
        add_poles=False,
    )


def _random_time(start: datetime, end: datetime) -> datetime:
    """Random datetime in [start, end].

    :param start: datetime start
    :type start: datetime
    :param end: datetime end
    :type end: datetime
    """

    delta = end - start
    return start + timedelta(seconds=random.uniform(0, delta.total_seconds()))


def render_and_save(
    cfg: StereoProjConfig,
    filename: str,
    random_angle: float,
    sample_dir: Path,
    teacher: bool = False,
):
    """Render helper."""

    catalog = Catalog(
        catalog_name="hip_data.tsv",
        use_cache=True,
    )

    # Create projector object with configuration
    constellation_cfg = None
    if teacher:
        constellation_cfg = ConstellationConfig(
            constellations_list=None,
            # Render all available constellations
            constellation_color="gray",
            constellation_linewidth=0.8,
            constellation_alpha=0.7,
            constellation_color_map=None,
        )

    # Create projector object with configuration
    projector = StereoProjector(
        config=cfg,
        catalog=catalog,
        planets_catalog=PlanetCatalog(),
        constellation_config=constellation_cfg,
        # Передаем конфигурацию созвездий
        random_angle=random_angle,
    )
    constraints = CatalogConstraints(
        max_magnitude=5.5,
    )

    fig, ax = projector.generate(constraints=constraints)

    save_figure_skychart(
        fig=fig,
        filename=str(sample_dir / filename),
        config=cfg,
        print_skychart_info=teacher,
    )

    plt.close(fig)


def generate_stereo_samples(
    number_of_samples: int,
    time_interval: tuple[datetime, datetime],
    folder_name: str,
    random_angle: float = np.random.uniform(0.0, 2 * np.pi),
):
    """Creates a folder with subfolders with skycharts.

    Each subfolder is generated by randomly choosing time in time_interval,
    latitude, longitude. In each subfolder there are 3 skycharts:
      1) student_cfg(add_planets=False)
      2) student_cfg(add_planets=True)
      3) teacher_cfg + print_skychart_info=True

    :param number_of_samples: number of samples to generate
    :type number_of_samples: int
    :param time_interval: the time interval from which a random time
        will be taken to generate the map
    :type time_interval: tuple[datetime, datetime]:
    :param folder_name: output folder name
    :type folder_name: str
    :param random_angle: North shift angle on the map
    :type random_angle: float:  (Default value = np.random.uniform(0, 2pi):
    """

    root = Path(folder_name)
    root.mkdir(parents=True, exist_ok=True)

    t_start, t_end = time_interval

    for i in range(number_of_samples):
        # Random observation params
        obs_time = _random_time(t_start, t_end)
        latitude = random.uniform(-90.0, 90.0)
        longitude = random.uniform(-180.0, 180.0)

        sample_dir = root / f"skychart_{i:03d}"
        sample_dir.mkdir(exist_ok=True)

        # Configs
        student_cfg_no_planets = get_student_cfg(
            time=obs_time,
            latitude=latitude,
            longitude=longitude,
            add_planets=False,
        )

        student_cfg_with_planets = get_student_cfg(
            time=obs_time,
            latitude=latitude,
            longitude=longitude,
            add_planets=True,
        )

        teacher_cfg = get_teacher_cfg(
            time=obs_time,
            latitude=latitude,
            longitude=longitude,
        )

        # ----------------------------
        # Generate charts
        # ----------------------------
        render_and_save(
            student_cfg_no_planets,
            "student_no_planets.pdf",
            random_angle=random_angle,
            sample_dir=sample_dir,
            teacher=False,
        )

        render_and_save(
            student_cfg_with_planets,
            "student_with_planets.pdf",
            random_angle=random_angle,
            sample_dir=sample_dir,
            teacher=False,
        )

        render_and_save(
            teacher_cfg,
            "teacher.pdf",
            random_angle=random_angle,
            sample_dir=sample_dir,
            teacher=True,
        )


if __name__ == "__main__":
    start_time = datetime(1984, 1, 1)
    end_time = datetime(2034, 1, 1)
    generate_stereo_samples(
        number_of_samples=100,
        time_interval=(start_time, end_time),
        folder_name="stereographic_samples",
    )
