from pathlib import Path
from typing import Any

import tetra3  # type: ignore
from pydantic import BaseModel, Field

from pixelemon.logging import pixelemon_LOG

TETRA_DATABASE_PATH = Path(__file__).parent / "tyc_db_to_40_deg.npz"


class TetraSolver(tetra3.Tetra3):
    def __init__(self, database_path: Path | None = None):
        if database_path is None:
            super().__init__()
        else:
            super().__init__(load_database=database_path.as_posix())
        self.settings = TetraSettings.model_validate(self.database_properties)

    @classmethod
    def low_memory(cls) -> "TetraSolver":
        solver = cls()
        pixelemon_LOG.info("Configured TetraSolver for low memory usage")
        return solver

    @classmethod
    def high_memory(cls) -> "TetraSolver":
        solver = cls(TETRA_DATABASE_PATH)
        pixelemon_LOG.info("Configured TetraSolver for high memory usage")
        return solver


class TetraSettings(BaseModel):
    dimmest_star_magnitude: float = Field(
        ...,
        description="The dimmest star magnitude to consider in the plate solve",
        alias="star_max_magnitude",
    )
    max_field_of_view: float = Field(
        ...,
        description="The maximum field of view in degrees the solver can reliably handle",
        alias="max_fov",
    )
    min_field_of_view: float = Field(
        ...,
        description="The minimum field of view in degrees the solver can reliably handle",
        alias="min_fov",
    )
    verification_star_count: int = Field(
        ...,
        description="The number of stars to use for verification of the plate solve",
        alias="verification_stars_per_fov",
    )

    def model_post_init(self, _: Any) -> None:
        pixelemon_LOG.info(f"Tetra dimmest star magnitude set to {self.dimmest_star_magnitude}")
        pixelemon_LOG.info(f"Tetra max field of view set to {self.max_field_of_view} degrees")
        pixelemon_LOG.info(f"Tetra min field of view set to {self.min_field_of_view} degrees")
        pixelemon_LOG.info(f"Tetra verification star count set to {self.verification_star_count}")


class PlateSolve(BaseModel):
    right_ascension: float = Field(
        ...,
        description="Right Ascension in degrees",
        alias="RA",
    )
    declination: float = Field(
        ...,
        description="Declination in degrees",
        alias="Dec",
    )
    roll: float = Field(
        ...,
        description="Roll angle in degrees",
        alias="Roll",
    )
    estimated_horizontal_fov: float = Field(
        ...,
        description="Estimated horizontal field of view in degrees",
        alias="FOV",
    )
    root_mean_square_error: float = Field(
        ...,
        description="Root mean square error of the plate solve in arcseconds",
        alias="RMSE",
    )
    number_of_stars: int = Field(
        ...,
        description="Number of stars used in the plate solve",
        alias="Matches",
    )
    false_positive_probability: float = Field(
        ...,
        description="Probability of a false positive plate solve",
        alias="Prob",
    )
    solve_time: float = Field(
        ...,
        description="Time taken to perform the plate solve in milliseconds",
        alias="T_solve",
    )


TETRA_SOLVER = TetraSolver.low_memory()
