# -*- coding: utf-8 -*-

# Copyright (c) 2021, Brandon Nielsen
# All rights reserved.
#
# This software may be modified and distributed under the terms
# of the BSD license.  See the LICENSE file for details.

from aniso8601.builders import TupleBuilder
from aniso8601.builders.python import PythonTimeBuilder
from aniso8601.compat import is_string
from aniso8601.exceptions import ISOFormatError
from aniso8601.resolution import DateResolution


def get_date_resolution(isodatestr):
    # Valid string formats are:
    #
    # Y[YYY]
    # YYYY-MM-DD
    # YYYYMMDD
    # YYYY-MM
    # YYYY-Www
    # YYYYWww
    # YYYY-Www-D
    # YYYYWwwD
    # YYYY-DDD
    # YYYYDDD
    isodatetuple = parse_date(isodatestr, builder=TupleBuilder)

    if isodatetuple.DDD is not None:
        # YYYY-DDD
        # YYYYDDD
        return DateResolution.Ordinal

    if isodatetuple.D is not None:
        # YYYY-Www-D
        # YYYYWwwD
        return DateResolution.Weekday

    if isodatetuple.Www is not None:
        # YYYY-Www
        # YYYYWww
        return DateResolution.Week

    if isodatetuple.DD is not None:
        # YYYY-MM-DD
        # YYYYMMDD
        return DateResolution.Day

    if isodatetuple.MM is not None:
        # YYYY-MM
        return DateResolution.Month

    # Y[YYY]
    return DateResolution.Year


def parse_date(isodatestr, builder=PythonTimeBuilder):
    # Given a string in any ISO 8601 date format, return a datetime.date
    # object that corresponds to the given date. Valid string formats are:
    #
    # Y[YYY]
    # YYYY-MM-DD
    # YYYYMMDD
    # YYYY-MM
    # YYYY-Www
    # YYYYWww
    # YYYY-Www-D
    # YYYYWwwD
    # YYYY-DDD
    # YYYYDDD
    if is_string(isodatestr) is False:
        raise ValueError("Date must be string.")

    if isodatestr.startswith("+") or isodatestr.startswith("-"):
        raise NotImplementedError(
            "ISO 8601 extended year representation " "not supported."
        )

    if len(isodatestr) == 0 or isodatestr.count("-") > 2:
        raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr))
    yearstr = None
    monthstr = None
    daystr = None
    weekstr = None
    weekdaystr = None
    ordinaldaystr = None

    if len(isodatestr) <= 4:
        # Y[YYY]
        yearstr = isodatestr
    elif "W" in isodatestr:
        if len(isodatestr) == 10:
            # YYYY-Www-D
            yearstr = isodatestr[0:4]
            weekstr = isodatestr[6:8]
            weekdaystr = isodatestr[9]
        elif len(isodatestr) == 8:
            if "-" in isodatestr:
                # YYYY-Www
                yearstr = isodatestr[0:4]
                weekstr = isodatestr[6:]
            else:
                # YYYYWwwD
                yearstr = isodatestr[0:4]
                weekstr = isodatestr[5:7]
                weekdaystr = isodatestr[7]
        elif len(isodatestr) == 7:
            # YYYYWww
            yearstr = isodatestr[0:4]
            weekstr = isodatestr[5:]
    elif len(isodatestr) == 7:
        if "-" in isodatestr:
            # YYYY-MM
            yearstr = isodatestr[0:4]
            monthstr = isodatestr[5:]
        else:
            # YYYYDDD
            yearstr = isodatestr[0:4]
            ordinaldaystr = isodatestr[4:]
    elif len(isodatestr) == 8:
        if "-" in isodatestr:
            # YYYY-DDD
            yearstr = isodatestr[0:4]
            ordinaldaystr = isodatestr[5:]
        else:
            # YYYYMMDD
            yearstr = isodatestr[0:4]
            monthstr = isodatestr[4:6]
            daystr = isodatestr[6:]
    elif len(isodatestr) == 10:
        # YYYY-MM-DD
        yearstr = isodatestr[0:4]
        monthstr = isodatestr[5:7]
        daystr = isodatestr[8:]
    else:
        raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr))

    hascomponent = False

    for componentstr in [yearstr, monthstr, daystr, weekstr, weekdaystr, ordinaldaystr]:
        if componentstr is not None:
            hascomponent = True

            if componentstr.isdigit() is False:
                raise ISOFormatError(
                    '"{0}" is not a valid ISO 8601 date.'.format(isodatestr)
                )

    if hascomponent is False:
        raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr))

    return builder.build_date(
        YYYY=yearstr,
        MM=monthstr,
        DD=daystr,
        Www=weekstr,
        D=weekdaystr,
        DDD=ordinaldaystr,
    )