import re

from tz_objects.dst_offset import DstOffset
from tz_objects.gmt_offset import GmtOffset
from tz_objects.tz_date_time import TzDateTime


class TimeZoneDatLine:
    """
       Example format for time_zone is:
       With DST - 'PST (GMT-08:00) FROM 14.03 02:00 TO 07.11 02:00 (GMT-07:00)'
       Without DST - 'ANC (GMT-09:00)'
       """
    TIME_ZONE_WITH_DST_REGEX = r"[a-zA-Z0-9]{3} \(GMT[+-]\d\d:\d\d\) FROM \d\d\.\d\d \d\d:\d\d TO \d\d\.\d\d \d\d:\d\d \(GMT[+-]\d\d:\d\d\)"
    TIME_ZONE_WITHOUT_DST_REGEX = r"[a-zA-Z0-9]{3} \(GMT[+-]\d\d:\d\d\)"

    def __init__(self, code: str = None, gmt_offset: GmtOffset = None,
                 tz_from: TzDateTime = None, tz_to: TzDateTime = None, dst_offset: GmtOffset = None, has_dst=False):
        self.code = code
        self.gmt_offset = gmt_offset
        self.tz_from = tz_from
        self.tz_to = tz_to
        self.dst_offset = dst_offset
        self.has_dst = has_dst

    #  line_pattern = r"""
    #     (?P<code>[A-Z]+)                                             # Code
    #     \s\(GMT(?P<gmt_offset.sign>[+-])(?P<gmt_offset.hour>\d{2}):(?P<gmt_offset.minute>\d{2})\)  # Timezone before 'FROM'
    #     (?:\sFROM\s(?P<tz_from.day>\d{2})\.(?P<tz_from.month>\d{2})\s      # Optional FROM date
    #     (?P<tz_from.hour>\d{2}):(?P<tz_from.minute>\d{2})                  # Optional FROM time
    #     \sTO\s(?P<tz_to.day>>\d{2})\.(?P<tz_to.month>\d{2})\s               # Optional TO date
    #     (?P<tz_to.hour>\d{2}):(?P<tz_to.minute>\d{2})                      # Optional TO time
    #     \s\(GMT(?P<dst_offset.sign>[+-])(?P<dst_offset.hour>\d{2}):(?P<dst_offset.minute>\d{2})\))? # Optional timezone after 'TO'
    # """
    #  self.line_regex = re.compile(line_pattern, re.VERBOSE)

    def to_str(self):
        parts = [f"{self.code} (GMT{self.gmt_offset.sign}{self.gmt_offset.hour}:{self.gmt_offset.minutes})"]
        if self.tz_from:
            parts.append(f"FROM {self.tz_from.day}.{self.tz_from.month} {self.tz_from.hours}:{self.tz_from.minutes}")
        if self.tz_to:
            parts.append(f"TO {self.tz_to.day}.{self.tz_to.month} {self.tz_to.hours}:{self.tz_to.minutes}")
        if self.dst_offset:
            parts.append(
                f"(GMT{self.dst_offset.sign}{self.dst_offset.hour}:{self.dst_offset.minutes})")
        return " ".join(parts)

        def parse_line(self, line):
            match = self.line_regex.search(line)
            if match:
                gmt_offset = GmtOffset()
                gmt_offset.sign = match.group("gmt_offset.sign")
                gmt_offset.hour = match.group("gmt_offset.hour")
                gmt_offset.minutes = match.group("gmt_offset.minutes")
                tz_from = TzDateTime()
                tz_from.day = match.group("tz_from.day")
                tz_from.month = match.group("tz_from.month")
                tz_from.year = match.group("tz_from.year")
                tz_from.hours = match.group("tz_from.hours")
                tz_from.minutes = match.group("tz_from.minutes")
                tz_to = TzDateTime()
                tz_to.day = match.group("tz_to.day")
                tz_to.month = match.group("tz_to.month")
                tz_to.year = match.group("tz_to.year")
                tz_to.hours = match.group("tz_to.hours")
                tz_to.minutes = match.group("tz_to.minutes")
                dst_offset = DstOffset()
                dst_offset.sign = match.group("dst_offset.sign")
                dst_offset.hour = match.group("dst_offset.hour")
                dst_offset.minutes = match.group("dst_offset.minutes")

                return TimeZoneDatLine(
                    code=match.group("code"),
                    gmt_offset=gmt_offset,
                    tz_from=tz_from,
                    tz_to=tz_to,
                    dst_offset=dst_offset
                )
            else:
                return None

    @staticmethod
    def parse_line(time_zone_line: str):
        return_time_Zone = TimeZoneDatLine()

        return_time_Zone.time_zone_json = None

        if bool(re.fullmatch(TimeZoneDatLine.TIME_ZONE_WITH_DST_REGEX, time_zone_line)):
            return_time_Zone.init_time_zone_with_dst(time_zone_line.split())
        elif bool(re.fullmatch(TimeZoneDatLine.TIME_ZONE_WITHOUT_DST_REGEX, time_zone_line)):
            return_time_Zone.init_time_zone_without_dst(time_zone_line.split())
        else:
            raise Exception(f"Invalid timezone format for line:\n{time_zone_line}")

        return return_time_Zone

    def init_time_zone_without_dst(self, time_zone_list):
        offset = GmtOffset.parse_str(time_zone_list[1])
        self.code = time_zone_list[0]
        self.gmt_offset = offset
        self.has_dst = False

    @staticmethod
    def is_dst_from_date_belong_to_south_hemisphere(dst_offset):
        # check if we are in south hemisphere by llokinbg on offset sign
        # because if we have south hemisphere  TimeZone.dat will contain the transfer to Winter watch(move clock one our back)
        # Example :Sydney is in therfore in TimeZone.dat it will apear as:
        #         SYD (GMT+11:00) FROM 07.04 03:00 TO 01.10 02:00 (GMT+10:00)
        #		  which means offset is negative (From +11:00 to +10:00)
        return dst_offset.sign == "-"

    @staticmethod
    def swap_objects(obj1, obj2):
        return obj2, obj1

    def init_time_zone_with_dst(self, time_zone_list):
        self.has_dst = True
        self.code = time_zone_list[0]
        self.gmt_offset = GmtOffset.parse_str(time_zone_list[1])
        self.dst_offset = GmtOffset.parse_str(time_zone_list[8])
        self.tz_from = TzDateTime(time_zone_list[3], time_zone_list[4])
