# from __future__ import annotations
# from typing import TYPE_CHECKING

# if TYPE_CHECKING:
#     from ..hoursselection import Hoursselection

# import logging
# from datetime import datetime
# from typing import Tuple
# import statistics as stat

# from .hoursselection_helpers import async_create_dict
# from .hourselection_calculations import (
#     normalize_prices,
#     async_create_cautions,
#     async_get_offset_dict,
#     async_should_be_cautionhour,
#     async_set_charge_allowance,
# )
# from ....models.hourselection.hourobjects.hourobject import HourObject
# from ....models.hourselection.hourobjects.hourobject_helpers import (
#     async_update_interim_lists,
# )
# from ....models.hourselection.day_types import DayTypes

# _LOGGER = logging.getLogger(__name__)


# class HourSelectionService:
#     def __init__(self, parent: Hoursselection, base_mock_hour: int | None = None):
#         self.parent = parent
#         self._mock_hour = base_mock_hour
#         self._mock_day: int | None = None
#         self.preserve_interim: bool = False
#         self._midnight_touched: bool = False

#     async def async_update(self) -> None:
#         if all(
#             [
#                 len(self.parent.model.prices_today) == 0,
#                 len(self.parent.model.prices_tomorrow) == 0,
#             ]
#         ):
#             return
#         if self.preserve_interim:
#             await self.async_change_midnight_data()
#         else:
#             self._midnight_touched = False
#             today = await self.async_update_per_day(
#                 prices=self.parent.model.prices_today, day_type=DayTypes.Today
#             )
#             tomorrow = await self.async_update_per_day(
#                 prices=self.parent.model.prices_tomorrow, day_type=DayTypes.Tomorrow
#             )
#             hours, hours_tomorrow = await self.async_interim_day_update(today, tomorrow)

#             self.parent.model.hours.hours_today = (
#                 await self.async_add_remove_limited_hours(
#                     hours, day_type=DayTypes.Today
#                 )
#             )
#             self.parent.model.hours.hours_tomorrow = (
#                 await self.async_add_remove_limited_hours(
#                     hours_tomorrow, day_type=DayTypes.Tomorrow
#                 )
#             )
#             hour = await self.async_set_hour()
#             await self.parent.model.hours.async_update_hour_lists(hour=hour)

#     async def async_change_midnight_data(self) -> None:
#         if self.parent.model.prices_tomorrow == []:
#             if not self._midnight_touched:
#                 self._midnight_touched = (
#                     await self.parent.model.hours.async_touch_midnight()
#                 )
#         else:
#             self.preserve_interim = False
#             await self.async_update()

#     async def async_update_per_day(
#         self, prices: list, day_type: DayTypes, range_start: int = 0
#     ) -> HourObject:
#         _LOGGER.debug(f"Updating {day_type.name}")
#         pricedict = {}
#         if prices is not None and len(prices) > 1:
#             pricedict = await async_create_dict(prices)
#             normalized_pricedict = await async_create_dict(normalize_prices(prices))
#             if stat.stdev(prices) > 0.05:
#                 ranked = await async_create_cautions(
#                     pricedict,
#                     normalized_pricedict,
#                     self.parent.cautionhour_type_enum,
#                     range_start,
#                     self.parent.model.adjusted_average,
#                     self.parent.model.options.blocknocturnal,
#                 )
#                 ready_hours = await self.async_determine_hours(ranked, prices)
#                 ret = HourObject(
#                     nh=ready_hours.nh,
#                     ch=ready_hours.ch,
#                     dyn_ch=ready_hours.dyn_ch,
#                     pricedict=pricedict,
#                 )
#             else:
#                 """the price curve is too flat to determine hours"""
#                 ret = HourObject(nh=[], ch=[], dyn_ch={}, pricedict=pricedict)
#             ret.offset_dict = await async_get_offset_dict(normalized_pricedict)
#             return ret
#         return HourObject([], [], {})

#     async def async_add_remove_limited_hours(
#         self, hours: HourObject, day_type: DayTypes
#     ) -> HourObject:
#         """Removes cheap hours and adds expensive hours set by user limitation"""
#         if hours is None or all(
#             [len(hours.nh) == 0, len(hours.ch) == 0, len(hours.dyn_ch) == 0]
#         ):
#             return HourObject(offset_dict=hours.offset_dict, pricedict=hours.pricedict)
#         match day_type:
#             case DayTypes.Today | DayTypes.Interim:
#                 await hours.async_add_expensive_hours(
#                     self.parent.model.options.absolute_top_price
#                 )
#             case DayTypes.Tomorrow:
#                 _top = await self.parent.model.options.async_add_tomorrow_to_top_price(
#                     self.parent.prices_tomorrow, self._mock_day
#                 )
#                 await hours.async_add_expensive_hours(_top)
#         return await hours.async_remove_cheap_hours(self.parent.model.options.min_price)

#     async def async_determine_hours(self, price_list: dict, prices: list) -> HourObject:
#         ret = HourObject([], [], {})
#         try:
#             for p in price_list:
#                 if price_list[p]["force_non"] is True:
#                     ret.nh.append(p)
#                 elif await async_should_be_cautionhour(
#                     price_list[p],
#                     prices,
#                     self.parent.model.current_peak,
#                     self.parent.model.options.cautionhour_type,
#                 ):
#                     ret.ch.append(p)
#                     ret.dyn_ch[p] = round(
#                         await async_set_charge_allowance(
#                             price_list[p]["permax"],
#                             self.parent.model.options.cautionhour_type,
#                         ),
#                         2,
#                     )
#                 else:
#                     ret.nh.append(p)
#         except IndexError as e:
#             _LOGGER.error(f"Error in determine hours: {e}")
#         return ret

#     async def async_interim_day_update(
#         self, today: HourObject, tomorrow: HourObject
#     ) -> Tuple[HourObject, HourObject]:
#         """Updates the non- and caution-hours with an adjusted mean of 14h - 13h today-tomorrow to get a more sane nightly curve."""
#         if len(self.parent.model.prices_tomorrow) < 23:
#             self.preserve_interim = False
#             return today, tomorrow

#         hour = await self.async_set_hour()
#         # hour = len(self.parent.prices) - 10
#         # negative_hour = hour * -1
#         negative_hour = (len(self.parent.prices) - hour) * -1
#         print(hour)
#         print(negative_hour)
#         pricelist = self.parent.model.prices_today[hour::]
#         pricelist[len(pricelist) :] = self.parent.model.prices_tomorrow[0:hour]
#         new_hours = await self.async_update_per_day(
#             prices=pricelist, range_start=hour, day_type=DayTypes.Interim
#         )

#         today = await async_update_interim_lists(
#             range(hour, len(self.parent.prices)), today, new_hours, hour
#         )
#         tomorrow = await async_update_interim_lists(
#             range(0, hour), tomorrow, new_hours, negative_hour
#         )
#         self.preserve_interim = True
#         return today, tomorrow

#     # helpers
#     def set_hour(self, testhour: int | None = None) -> int:
#         return (
#             testhour
#             if testhour is not None
#             else self._mock_hour
#             if self._mock_hour is not None
#             else datetime.now().hour
#         )

#     async def async_set_hour(self, testhour: int | None = None) -> int:
#         return (
#             testhour
#             if testhour is not None
#             else self._mock_hour
#             if self._mock_hour is not None
#             else datetime.now().hour
#         )

#     async def async_set_day(self, day: int | None = None):
#         self._mock_day = day if day is not None else datetime.now().day
