#!/usr/bin/python3
#
# Copyright (C) 2025 Red Hat, Inc.
# SPDX-License-Identifier: LGPL-2.1-or-later

import datetime
from zoneinfo import ZoneInfo

from anacondalib import VirtInstallMachineCase
from installer import Installer
from language import Language
from review import Review
from testlib import nondestructive, test_main
from timezone import DateAndTime


@nondestructive
class TestDateAndTime(VirtInstallMachineCase):

    def setUp(self):
        super().setUp()

    def testDefaultState(self):
        """
        Description:
            Test default state picked up from backend

        Expected results:
            - WebUI auto date/time and timezone matches backend
            - NTP, timezone, date and time match backend
            - The selected timezone is displayed in the Review screen
        """
        b = self.browser
        m = self.machine
        i = Installer(b, m)
        r = Review(b, m)
        dt = DateAndTime(b, m)

        default_timezone = dt.dbus_get_timezone()

        i.open()
        i.reach(i.steps.DATE_TIME)
        dt.check_auto_date_time(dt.dbus_get_ntp_enabled())
        dt.check_auto_timezone(True)
        region, city = default_timezone.split('/', 1)
        dt.check_region(region)
        dt.check_city(city)

        i.reach(i.steps.REVIEW)
        r.check_timezone(default_timezone)

    def testNtpServerSelection(self):
        """
        Description:
            Test selecting custom NTP server.

        Expected Results:
            - The default NTP servers are loaded from the chronyd configuration
            - The user can configure a custom NTP server in the UI
        """
        b = self.browser
        m = self.machine
        i = Installer(b, m)
        dt = DateAndTime(b, m)

        i.open()
        i.reach(i.steps.DATE_TIME)
        dt.set_auto_date_time(True)
        dt.dbus_clear_time_sources()

        b.click(f"#{i.steps.DATE_TIME}-configure-ntp")
        dt.check_ntp_server_enabled("2.fedora.pool.ntp.org", 0)

        dt.add_ntp_server("europe.pool.ntp.org", 1)

    def testManualDateTimeTimezoneAndFormat(self):
        """
        Description:
            Test manual setting of time, date, timezone and time format.

        Expected results:
            - Time and date are manually set and reflected in backend
            - Manual timezone selection changes timezone on backend
            - Switching between 24h and AM/PM format works as expected
        """
        b = self.browser
        m = self.machine
        i = Installer(b, m)
        dt = DateAndTime(b, m)
        lang = Language(b, m)

        i.open()
        lang.select_locale("de_DE")
        i.reach(i.steps.DATE_TIME)

        dt.set_auto_date_time(False)
        dt.set_date("2025-01-01")
        dt.set_time("19:00")
        dt.check_date("2025-01-01")
        dt.check_time("19:00")

        dt.set_time_format("ampm")
        dt.check_time_format("ampm")
        dt.check_time("07:00 PM")

        dt.set_time_format("24")
        dt.check_time_format("24")
        dt.check_time("19:00")

        dt.set_auto_timezone(False)
        dt.select_region("America")
        dt.select_city("Sao_Paulo")
        dt.check_timezone_label("GMT-3, UTC-3")
        self.assertEqual(dt.dbus_get_timezone(), "America/Sao_Paulo")

        # Test timezone with multiple cities (same region)
        dt.select_city("Argentina/Buenos_Aires")
        dt.check_timezone_label("GMT-3, UTC-3")
        self.assertEqual(dt.dbus_get_timezone(), "America/Argentina/Buenos_Aires")

    def testTimezoneAndTimeFormat(self):
        """
        Description:
            Test full cycle of setting time zone, time format (24h/AMPM), date/time,
            and verify correct UTC conversion on the backend.

        Expected results:
            - User can manually disable automatic time and timezone settings.
            - Time format can be switched between 24h and AM/PM, and is correctly reflected in the UI.
            - Timezone selection (e.g., America/New_York, Asia/Tokyo) updates both the label and backend value.
            - The backend datetime is correctly calculated and stored in UTC regardless of selected timezone.
            - Setting local time in one timezone correctly adjusts backend UTC time.
        """
        b = self.browser
        m = self.machine
        i = Installer(b, m)
        dt = DateAndTime(b, m)

        i.open()
        i.reach(i.steps.DATE_TIME)
        dt.set_auto_date_time(False)
        dt.set_auto_timezone(False)

        dt.set_time_format("24")
        dt.check_time_format("24")
        dt.select_region("America")
        dt.select_city("New_York")
        self.assertEqual(dt.dbus_get_timezone(), "America/New_York")

        dt.set_date("2025-01-31")
        dt.set_time("15:45")

        dt.set_time_format("ampm")
        dt.check_time_format("ampm")
        dt.check_time("03:45 PM")

        dt.set_time_format("24")
        dt.check_time_format("24")
        dt.check_time("15:45")

        backend_iso = dt.dbus_get_system_datetime()
        dt_parsed = datetime.datetime.fromisoformat(backend_iso)
        dt_utc = dt_parsed.astimezone(datetime.timezone.utc)

        expected_utc = datetime.datetime(2025, 1, 31, 20, 45, tzinfo=datetime.timezone.utc)
        assert dt_utc.strftime("%Y-%m-%dT%H:%M") == expected_utc.strftime("%Y-%m-%dT%H:%M")

        dt.select_region("Asia")
        dt.select_city("Tokyo")
        self.assertEqual(dt.dbus_get_timezone(), "Asia/Tokyo")

        dt.check_time("05:45")
        dt.set_time("00:45")

        dt.set_time_format("ampm")
        dt.check_time_format("ampm")
        dt.check_time("12:45 AM")

        dt.set_time_format("24")
        dt.check_time_format("24")
        dt.set_time("08:00")

        local_tokyo = datetime.datetime(2025, 2, 1, 8, 0, tzinfo=ZoneInfo("Asia/Tokyo"))
        backend_iso3 = dt.dbus_get_system_datetime()
        self.assertTrue(
            backend_iso3.startswith(local_tokyo.strftime("%Y-%m-%dT%H:%M")),
            f"Expected backend local time {local_tokyo}, got {backend_iso3}"
        )


if __name__ == '__main__':
    test_main()
