"""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 src.helpers.pdf_helpers.figure2pdf import save_figure_skychart
from src.hip_catalog.hip_catalog import Catalog, CatalogConstraints
from src.planets_catalog.planet_catalog import PlanetCatalog
from src.stereographic_projection.stereographic_projector 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",
    )
