"""MessageMaker for r.gnode.regp.sync.req.1_0_0"""

import datetime
import time
import uuid
from typing import Any
from typing import Dict
from typing import List
from typing import Optional
from typing import Tuple

from gridworks.errors import *

import gwatn.types.hack_test_dummy as test_dummy
from gwatn.types.gnode_regprequest_ps.r_gnode_regp_sync_req.r_gnode_regp_sync_req_1_0_0_payload import (
    Payload,
)
from gwatn.types.hack_type_base import HackTypeBase
from gwatn.types.hack_utils import log_style_utc_date_w_millis


class R_Gnode_Regp_Sync_Req_1_0_0(HackTypeBase):
    mp_alias = "r.gnode.regp.sync.req.1_0_0"
    routing_key_base = "gnode.regprequest.ps"

    @classmethod
    def create_payload_from_camel_dict(cls, d: dict) -> Payload:
        if "MpAlias" not in d.keys():
            d["MpAlias"] = "r.gnode.regp.sync.req.1_0_0"
        if "IrlTimeUtc" not in d.keys():
            d["IrlTimeUtc"] = None
        if "PriceUid" not in d.keys():
            d["PriceUid"] = None
        if "WorldInstanceAlias" not in d.keys():
            d["WorldInstanceAlias"] = None
        p = Payload(
            MpAlias=d["MpAlias"],
            UniformSliceDurationHrs=float(d["UniformSliceDurationHrs"]),
            FromGNodeInstanceId=d["FromGNodeInstanceId"],
            TotalSlices=d["TotalSlices"],
            PNodeAlias=d["PNodeAlias"],
            TimezoneString=d["TimezoneString"],
            FromGNodeAlias=d["FromGNodeAlias"],
            MessageId=d["MessageId"],
            StartDayUtc=d["StartDayUtc"],
            ToGNodeAlias=d["ToGNodeAlias"],
            IrlTimeUtc=d["IrlTimeUtc"],
            StartYearUtc=d["StartYearUtc"],
            MethodAlias=d["MethodAlias"],
            CurrencyUnit=d["CurrencyUnit"],
            StartMonthUtc=d["StartMonthUtc"],
            StartHourUtc=d["StartHourUtc"],
            StartMinuteUtc=d["StartMinuteUtc"],
            PriceUid=d["PriceUid"],
            WorldInstanceAlias=d["WorldInstanceAlias"],
        )
        is_valid, errors = p.is_valid()
        if not is_valid:
            raise SchemaError(errors)
        return p

    @classmethod
    def payload_is_valid(
        cls, payload_as_dict: Dict[str, Any]
    ) -> Tuple[bool, Optional[List[str]]]:
        try:
            p = cls.create_payload_from_camel_dict(payload_as_dict)
        except SchemaError as e:
            errors = [e]
            return False, errors
        return p.is_valid()

    def __init__(
        self,
        agent,
        to_g_node_alias: str,
        uniform_slice_duration_hrs: float,
        total_slices: int,
        p_node_alias: str,
        timezone_string: str,
        start_utc: datetime.datetime,
        method_alias: str,
        currency_unit: str,
        irl_time_utc: Optional[str] = None,
        price_uid: Optional[str] = None,
    ):
        super().__init__(routing_key_base="gnode.regprequest.ps", agent=agent)
        self.errors = []
        self.payload = None
        if agent is None:
            raise Exception(
                f"Message protocol {R_Gnode_Regp_Sync_Req_1_0_0.mp_alias} must be generated by a message agent"
            )
        if agent == test_dummy.TEST_DUMMY_AGENT:
            from_g_node_alias = test_dummy.TEST_DUMMY_G_NODE_ALIAS
            from_g_node_instance_id = test_dummy.TEST_DUMMY_G_NODE_INSTANCE_ID
            world_instance_alias = test_dummy.TEST_DUMMY_WORLD_INSTANCE_ALIAS
            irl_time_utc = log_style_utc_date_w_millis(time.time())
        else:
            if not agent.gni.g_node.is_g_node:
                raise Exception(
                    f"Message protocol {R_Gnode_Regp_Sync_Req_1_0_0.mp_alias} must come from a GNode"
                )
            from_g_node_alias = agent.gni.g_node.alias
            from_g_node_instance_id = agent.gni.g_node_instance_id
            if agent.world_instance.is_simulated:
                world_instance_alias = agent.world_instance.alias
            else:
                world_instance_alias = None
            if agent.is_debug_mode:
                irl_time_utc = log_style_utc_date_w_millis(time.time())
            else:
                irl_time_utc = None
        try:
            uniform_slice_duration_hrs = float(uniform_slice_duration_hrs)
        except ValueError:
            pass  # This will get caught in is_valid() check below

        p = Payload(
            MpAlias=R_Gnode_Regp_Sync_Req_1_0_0.mp_alias,
            WorldInstanceAlias=world_instance_alias,
            FromGNodeAlias=from_g_node_alias,
            FromGNodeInstanceId=from_g_node_instance_id,
            ToGNodeAlias=to_g_node_alias,
            UniformSliceDurationHrs=uniform_slice_duration_hrs,
            TotalSlices=total_slices,
            PNodeAlias=p_node_alias,
            TimezoneString=timezone_string,
            StartDayUtc=start_utc.day,
            IrlTimeUtc=irl_time_utc,
            StartYearUtc=start_utc.year,
            MethodAlias=method_alias,
            CurrencyUnit=currency_unit,
            StartMonthUtc=start_utc.month,
            StartHourUtc=start_utc.hour,
            StartMinuteUtc=start_utc.minute,
            PriceUid=price_uid,
            MessageId=str(uuid.uuid4()),
        )

        is_valid, errors = p.is_valid()
        if is_valid is False:
            raise SchemaError(f"Failed to create payload due to these errors: {errors}")
        self.payload = p
