from __future__ import annotations

import datetime
from collections.abc import Mapping
from typing import Any, Literal, TypeVar, cast

from attrs import define as _attrs_define
from attrs import field as _attrs_field
from dateutil.parser import isoparse

from ..models.cron_schedule_day_mode import CronScheduleDayMode
from ..models.cron_schedule_day_of_week_type_0_item import CronScheduleDayOfWeekType0Item
from ..models.cron_schedule_day_of_week_type_1 import CronScheduleDayOfWeekType1
from ..models.cron_schedule_hour_mode import CronScheduleHourMode
from ..models.cron_schedule_minute_mode import CronScheduleMinuteMode
from ..models.cron_schedule_month_mode import CronScheduleMonthMode
from ..models.cron_schedule_week_mode import CronScheduleWeekMode
from ..models.timezone_enum import TimezoneEnum
from ..types import UNSET, Unset

T = TypeVar("T", bound="CronSchedule")


@_attrs_define
class CronSchedule:
    """
    Attributes:
        trigger (Literal['cron'] | Unset):  Default: 'cron'.
        minute (int | None | Unset): minute (0-59)
        hour (int | None | Unset): hour (0-23)
        day (int | None | Unset): day of month (1-31)
        day_of_week (CronScheduleDayOfWeekType1 | list[CronScheduleDayOfWeekType0Item] | None | Unset): number mapped
            name of weekday (0-6 or mon,tue,wed,thu,fri,sat,sun)
        week (int | None | Unset): ISO week (1-53)
        month (int | None | Unset): month (1-12)
        year (int | None | Unset): 4-digit year
        start_date (datetime.datetime | None | Unset): earliest possible date/time to trigger on (inclusive)
        end_date (datetime.datetime | None | Unset): latest possible date/time to trigger on (inclusive)
        timezone (None | TimezoneEnum | Unset): time zone to use for the date/time calculations (defaults to scheduler
            timezone)
        jitter (int | None | Unset): delay the job execution by ``jitter`` seconds at most
        minute_mode (CronScheduleMinuteMode | Unset):  Default: CronScheduleMinuteMode.AT.
        hour_mode (CronScheduleHourMode | Unset):  Default: CronScheduleHourMode.AT.
        day_mode (CronScheduleDayMode | Unset):  Default: CronScheduleDayMode.AT.
        week_mode (CronScheduleWeekMode | Unset):  Default: CronScheduleWeekMode.AT.
        month_mode (CronScheduleMonthMode | Unset):  Default: CronScheduleMonthMode.AT.
    """

    trigger: Literal["cron"] | Unset = "cron"
    minute: int | None | Unset = UNSET
    hour: int | None | Unset = UNSET
    day: int | None | Unset = UNSET
    day_of_week: CronScheduleDayOfWeekType1 | list[CronScheduleDayOfWeekType0Item] | None | Unset = UNSET
    week: int | None | Unset = UNSET
    month: int | None | Unset = UNSET
    year: int | None | Unset = UNSET
    start_date: datetime.datetime | None | Unset = UNSET
    end_date: datetime.datetime | None | Unset = UNSET
    timezone: None | TimezoneEnum | Unset = UNSET
    jitter: int | None | Unset = UNSET
    minute_mode: CronScheduleMinuteMode | Unset = CronScheduleMinuteMode.AT
    hour_mode: CronScheduleHourMode | Unset = CronScheduleHourMode.AT
    day_mode: CronScheduleDayMode | Unset = CronScheduleDayMode.AT
    week_mode: CronScheduleWeekMode | Unset = CronScheduleWeekMode.AT
    month_mode: CronScheduleMonthMode | Unset = CronScheduleMonthMode.AT
    additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)

    def to_dict(self) -> dict[str, Any]:
        trigger = self.trigger

        minute: int | None | Unset
        if isinstance(self.minute, Unset):
            minute = UNSET
        else:
            minute = self.minute

        hour: int | None | Unset
        if isinstance(self.hour, Unset):
            hour = UNSET
        else:
            hour = self.hour

        day: int | None | Unset
        if isinstance(self.day, Unset):
            day = UNSET
        else:
            day = self.day

        day_of_week: list[str] | None | str | Unset
        if isinstance(self.day_of_week, Unset):
            day_of_week = UNSET
        elif isinstance(self.day_of_week, list):
            day_of_week = []
            for day_of_week_type_0_item_data in self.day_of_week:
                day_of_week_type_0_item = day_of_week_type_0_item_data.value
                day_of_week.append(day_of_week_type_0_item)

        elif isinstance(self.day_of_week, CronScheduleDayOfWeekType1):
            day_of_week = self.day_of_week.value
        else:
            day_of_week = self.day_of_week

        week: int | None | Unset
        if isinstance(self.week, Unset):
            week = UNSET
        else:
            week = self.week

        month: int | None | Unset
        if isinstance(self.month, Unset):
            month = UNSET
        else:
            month = self.month

        year: int | None | Unset
        if isinstance(self.year, Unset):
            year = UNSET
        else:
            year = self.year

        start_date: None | str | Unset
        if isinstance(self.start_date, Unset):
            start_date = UNSET
        elif isinstance(self.start_date, datetime.datetime):
            start_date = self.start_date.isoformat()
        else:
            start_date = self.start_date

        end_date: None | str | Unset
        if isinstance(self.end_date, Unset):
            end_date = UNSET
        elif isinstance(self.end_date, datetime.datetime):
            end_date = self.end_date.isoformat()
        else:
            end_date = self.end_date

        timezone: None | str | Unset
        if isinstance(self.timezone, Unset):
            timezone = UNSET
        elif isinstance(self.timezone, TimezoneEnum):
            timezone = self.timezone.value
        else:
            timezone = self.timezone

        jitter: int | None | Unset
        if isinstance(self.jitter, Unset):
            jitter = UNSET
        else:
            jitter = self.jitter

        minute_mode: str | Unset = UNSET
        if not isinstance(self.minute_mode, Unset):
            minute_mode = self.minute_mode.value

        hour_mode: str | Unset = UNSET
        if not isinstance(self.hour_mode, Unset):
            hour_mode = self.hour_mode.value

        day_mode: str | Unset = UNSET
        if not isinstance(self.day_mode, Unset):
            day_mode = self.day_mode.value

        week_mode: str | Unset = UNSET
        if not isinstance(self.week_mode, Unset):
            week_mode = self.week_mode.value

        month_mode: str | Unset = UNSET
        if not isinstance(self.month_mode, Unset):
            month_mode = self.month_mode.value

        field_dict: dict[str, Any] = {}
        field_dict.update(self.additional_properties)
        field_dict.update({})
        if trigger is not UNSET:
            field_dict["trigger"] = trigger
        if minute is not UNSET:
            field_dict["minute"] = minute
        if hour is not UNSET:
            field_dict["hour"] = hour
        if day is not UNSET:
            field_dict["day"] = day
        if day_of_week is not UNSET:
            field_dict["day_of_week"] = day_of_week
        if week is not UNSET:
            field_dict["week"] = week
        if month is not UNSET:
            field_dict["month"] = month
        if year is not UNSET:
            field_dict["year"] = year
        if start_date is not UNSET:
            field_dict["start_date"] = start_date
        if end_date is not UNSET:
            field_dict["end_date"] = end_date
        if timezone is not UNSET:
            field_dict["timezone"] = timezone
        if jitter is not UNSET:
            field_dict["jitter"] = jitter
        if minute_mode is not UNSET:
            field_dict["minute_mode"] = minute_mode
        if hour_mode is not UNSET:
            field_dict["hour_mode"] = hour_mode
        if day_mode is not UNSET:
            field_dict["day_mode"] = day_mode
        if week_mode is not UNSET:
            field_dict["week_mode"] = week_mode
        if month_mode is not UNSET:
            field_dict["month_mode"] = month_mode

        return field_dict

    @classmethod
    def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
        d = dict(src_dict)
        trigger = cast(Literal["cron"] | Unset, d.pop("trigger", UNSET))
        if trigger != "cron" and not isinstance(trigger, Unset):
            raise ValueError(f"trigger must match const 'cron', got '{trigger}'")

        def _parse_minute(data: object) -> int | None | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            return cast(int | None | Unset, data)

        minute = _parse_minute(d.pop("minute", UNSET))

        def _parse_hour(data: object) -> int | None | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            return cast(int | None | Unset, data)

        hour = _parse_hour(d.pop("hour", UNSET))

        def _parse_day(data: object) -> int | None | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            return cast(int | None | Unset, data)

        day = _parse_day(d.pop("day", UNSET))

        def _parse_day_of_week(
            data: object,
        ) -> CronScheduleDayOfWeekType1 | list[CronScheduleDayOfWeekType0Item] | None | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            try:
                if not isinstance(data, list):
                    raise TypeError()
                day_of_week_type_0 = []
                _day_of_week_type_0 = data
                for day_of_week_type_0_item_data in _day_of_week_type_0:
                    day_of_week_type_0_item = CronScheduleDayOfWeekType0Item(day_of_week_type_0_item_data)

                    day_of_week_type_0.append(day_of_week_type_0_item)

                return day_of_week_type_0
            except (TypeError, ValueError, AttributeError, KeyError):
                pass
            try:
                if not isinstance(data, str):
                    raise TypeError()
                day_of_week_type_1 = CronScheduleDayOfWeekType1(data)

                return day_of_week_type_1
            except (TypeError, ValueError, AttributeError, KeyError):
                pass
            return cast(CronScheduleDayOfWeekType1 | list[CronScheduleDayOfWeekType0Item] | None | Unset, data)

        day_of_week = _parse_day_of_week(d.pop("day_of_week", UNSET))

        def _parse_week(data: object) -> int | None | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            return cast(int | None | Unset, data)

        week = _parse_week(d.pop("week", UNSET))

        def _parse_month(data: object) -> int | None | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            return cast(int | None | Unset, data)

        month = _parse_month(d.pop("month", UNSET))

        def _parse_year(data: object) -> int | None | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            return cast(int | None | Unset, data)

        year = _parse_year(d.pop("year", UNSET))

        def _parse_start_date(data: object) -> datetime.datetime | None | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            try:
                if not isinstance(data, str):
                    raise TypeError()
                start_date_type_0 = isoparse(data)

                return start_date_type_0
            except (TypeError, ValueError, AttributeError, KeyError):
                pass
            return cast(datetime.datetime | None | Unset, data)

        start_date = _parse_start_date(d.pop("start_date", UNSET))

        def _parse_end_date(data: object) -> datetime.datetime | None | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            try:
                if not isinstance(data, str):
                    raise TypeError()
                end_date_type_0 = isoparse(data)

                return end_date_type_0
            except (TypeError, ValueError, AttributeError, KeyError):
                pass
            return cast(datetime.datetime | None | Unset, data)

        end_date = _parse_end_date(d.pop("end_date", UNSET))

        def _parse_timezone(data: object) -> None | TimezoneEnum | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            try:
                if not isinstance(data, str):
                    raise TypeError()
                timezone_type_0 = TimezoneEnum(data)

                return timezone_type_0
            except (TypeError, ValueError, AttributeError, KeyError):
                pass
            return cast(None | TimezoneEnum | Unset, data)

        timezone = _parse_timezone(d.pop("timezone", UNSET))

        def _parse_jitter(data: object) -> int | None | Unset:
            if data is None:
                return data
            if isinstance(data, Unset):
                return data
            return cast(int | None | Unset, data)

        jitter = _parse_jitter(d.pop("jitter", UNSET))

        _minute_mode = d.pop("minute_mode", UNSET)
        minute_mode: CronScheduleMinuteMode | Unset
        if isinstance(_minute_mode, Unset):
            minute_mode = UNSET
        else:
            minute_mode = CronScheduleMinuteMode(_minute_mode)

        _hour_mode = d.pop("hour_mode", UNSET)
        hour_mode: CronScheduleHourMode | Unset
        if isinstance(_hour_mode, Unset):
            hour_mode = UNSET
        else:
            hour_mode = CronScheduleHourMode(_hour_mode)

        _day_mode = d.pop("day_mode", UNSET)
        day_mode: CronScheduleDayMode | Unset
        if isinstance(_day_mode, Unset):
            day_mode = UNSET
        else:
            day_mode = CronScheduleDayMode(_day_mode)

        _week_mode = d.pop("week_mode", UNSET)
        week_mode: CronScheduleWeekMode | Unset
        if isinstance(_week_mode, Unset):
            week_mode = UNSET
        else:
            week_mode = CronScheduleWeekMode(_week_mode)

        _month_mode = d.pop("month_mode", UNSET)
        month_mode: CronScheduleMonthMode | Unset
        if isinstance(_month_mode, Unset):
            month_mode = UNSET
        else:
            month_mode = CronScheduleMonthMode(_month_mode)

        cron_schedule = cls(
            trigger=trigger,
            minute=minute,
            hour=hour,
            day=day,
            day_of_week=day_of_week,
            week=week,
            month=month,
            year=year,
            start_date=start_date,
            end_date=end_date,
            timezone=timezone,
            jitter=jitter,
            minute_mode=minute_mode,
            hour_mode=hour_mode,
            day_mode=day_mode,
            week_mode=week_mode,
            month_mode=month_mode,
        )

        cron_schedule.additional_properties = d
        return cron_schedule

    @property
    def additional_keys(self) -> list[str]:
        return list(self.additional_properties.keys())

    def __getitem__(self, key: str) -> Any:
        return self.additional_properties[key]

    def __setitem__(self, key: str, value: Any) -> None:
        self.additional_properties[key] = value

    def __delitem__(self, key: str) -> None:
        del self.additional_properties[key]

    def __contains__(self, key: str) -> bool:
        return key in self.additional_properties
