"""
Tests for Themis utility functions.
"""
from datetime import date, datetime, time
from unittest.mock import MagicMock
from zoneinfo import ZoneInfo

from django.contrib.auth import get_user_model
from django.test import TestCase

from themis.utils import (
    convert_to_user_timezone,
    format_date_for_user,
    format_number_for_user,
    format_time_for_user,
    get_effective_theme,
    get_timezone_display,
)

User = get_user_model()


class ConvertToUserTimezoneTest(TestCase):
    """Tests for convert_to_user_timezone."""

    def setUp(self):
        self.user = User.objects.create_user(username="tzutil", password="pass123")
        self.user.profile.home_timezone = "America/Toronto"
        self.user.profile.save()

    def test_aware_datetime_converted(self):
        """Aware datetime is converted to user's timezone."""
        dt = datetime(2024, 6, 15, 12, 0, 0, tzinfo=ZoneInfo("UTC"))
        result = convert_to_user_timezone(dt, self.user)
        self.assertEqual(str(result.tzinfo), "America/Toronto")
        self.assertEqual(result.hour, 8)  # UTC-4 in summer (EDT)

    def test_naive_datetime_assumed_utc(self):
        """Naive datetime is assumed UTC and converted."""
        dt = datetime(2024, 6, 15, 12, 0, 0)
        result = convert_to_user_timezone(dt, self.user)
        self.assertEqual(str(result.tzinfo), "America/Toronto")

    def test_user_without_profile(self):
        """User without profile returns datetime unchanged."""
        user_no_profile = MagicMock(spec=[])
        dt = datetime(2024, 6, 15, 12, 0, 0, tzinfo=ZoneInfo("UTC"))
        result = convert_to_user_timezone(dt, user_no_profile)
        self.assertEqual(result, dt)

    def test_traveling_user(self):
        """Traveling user's current timezone is used."""
        self.user.profile.current_timezone = "Asia/Tokyo"
        self.user.profile.save()
        dt = datetime(2024, 6, 15, 12, 0, 0, tzinfo=ZoneInfo("UTC"))
        result = convert_to_user_timezone(dt, self.user)
        self.assertEqual(str(result.tzinfo), "Asia/Tokyo")
        self.assertEqual(result.hour, 21)  # UTC+9


class GetTimezoneDisplayTest(TestCase):
    """Tests for get_timezone_display."""

    def test_returns_user_timezone(self):
        """Returns user's effective timezone name."""
        user = User.objects.create_user(username="disptz", password="pass123")
        user.profile.home_timezone = "Europe/London"
        user.profile.save()
        self.assertEqual(get_timezone_display(user), "Europe/London")

    def test_returns_utc_for_no_profile(self):
        """Returns UTC for user without profile."""
        user_no_profile = MagicMock(spec=[])
        self.assertEqual(get_timezone_display(user_no_profile), "UTC")


class FormatDateForUserTest(TestCase):
    """Tests for format_date_for_user."""

    def setUp(self):
        self.user = User.objects.create_user(username="datefmt", password="pass123")
        self.test_date = date(2024, 12, 25)

    def test_iso_format(self):
        """YYYY-MM-DD format."""
        self.user.profile.date_format = "YYYY-MM-DD"
        self.user.profile.save()
        self.assertEqual(format_date_for_user(self.test_date, self.user), "2024-12-25")

    def test_dd_slash_mm_slash_yyyy(self):
        """DD/MM/YYYY format."""
        self.user.profile.date_format = "DD/MM/YYYY"
        self.user.profile.save()
        self.assertEqual(format_date_for_user(self.test_date, self.user), "25/12/2024")

    def test_mm_slash_dd_slash_yyyy(self):
        """MM/DD/YYYY format."""
        self.user.profile.date_format = "MM/DD/YYYY"
        self.user.profile.save()
        self.assertEqual(format_date_for_user(self.test_date, self.user), "12/25/2024")

    def test_dd_dot_mm_dot_yyyy(self):
        """DD.MM.YYYY format."""
        self.user.profile.date_format = "DD.MM.YYYY"
        self.user.profile.save()
        self.assertEqual(format_date_for_user(self.test_date, self.user), "25.12.2024")

    def test_dd_dash_mm_dash_yyyy(self):
        """DD-MM-YYYY format."""
        self.user.profile.date_format = "DD-MM-YYYY"
        self.user.profile.save()
        self.assertEqual(format_date_for_user(self.test_date, self.user), "25-12-2024")

    def test_no_profile_fallback(self):
        """Falls back to ISO format for user without profile."""
        user_no_profile = MagicMock(spec=[])
        self.assertEqual(
            format_date_for_user(self.test_date, user_no_profile), "2024-12-25"
        )


class FormatTimeForUserTest(TestCase):
    """Tests for format_time_for_user."""

    def setUp(self):
        self.user = User.objects.create_user(username="timefmt", password="pass123")

    def test_24_hour_format(self):
        """24-hour format."""
        self.user.profile.time_format = "24-hour"
        self.user.profile.save()
        t = time(15, 30)
        self.assertEqual(format_time_for_user(t, self.user), "15:30")

    def test_12_hour_format(self):
        """12-hour format."""
        self.user.profile.time_format = "12-hour"
        self.user.profile.save()
        t = time(15, 30)
        self.assertEqual(format_time_for_user(t, self.user), "03:30 PM")

    def test_midnight_24_hour(self):
        """Midnight in 24-hour format."""
        self.user.profile.time_format = "24-hour"
        self.user.profile.save()
        t = time(0, 0)
        self.assertEqual(format_time_for_user(t, self.user), "00:00")

    def test_midnight_12_hour(self):
        """Midnight in 12-hour format."""
        self.user.profile.time_format = "12-hour"
        self.user.profile.save()
        t = time(0, 0)
        self.assertEqual(format_time_for_user(t, self.user), "12:00 AM")

    def test_no_profile_fallback(self):
        """Falls back to 24-hour for user without profile."""
        user_no_profile = MagicMock(spec=[])
        t = time(15, 30)
        self.assertEqual(format_time_for_user(t, user_no_profile), "15:30")


class FormatNumberForUserTest(TestCase):
    """Tests for format_number_for_user."""

    def setUp(self):
        self.user = User.objects.create_user(username="numfmt", password="pass123")

    def test_comma_separator(self):
        """Comma thousand separator (default)."""
        self.user.profile.thousand_separator = "comma"
        self.user.profile.save()
        self.assertEqual(format_number_for_user(1000000, self.user), "1,000,000")

    def test_period_separator(self):
        """Period thousand separator."""
        self.user.profile.thousand_separator = "period"
        self.user.profile.save()
        self.assertEqual(format_number_for_user(1000000, self.user), "1.000.000")

    def test_space_separator(self):
        """Space (non-breaking) thousand separator."""
        self.user.profile.thousand_separator = "space"
        self.user.profile.save()
        result = format_number_for_user(1000000, self.user)
        self.assertIn("\u00a0", result)
        self.assertEqual(result, "1\u00a0000\u00a0000")

    def test_no_separator(self):
        """No thousand separator."""
        self.user.profile.thousand_separator = "none"
        self.user.profile.save()
        self.assertEqual(format_number_for_user(1000000, self.user), "1000000")

    def test_small_number(self):
        """Numbers under 1000 have no separator."""
        self.user.profile.thousand_separator = "comma"
        self.user.profile.save()
        self.assertEqual(format_number_for_user(999, self.user), "999")

    def test_no_profile_fallback(self):
        """Falls back to comma separator for user without profile."""
        user_no_profile = MagicMock(spec=[])
        self.assertEqual(format_number_for_user(1000, user_no_profile), "1,000")


class GetEffectiveThemeTest(TestCase):
    """Tests for get_effective_theme."""

    def setUp(self):
        self.user = User.objects.create_user(username="themeutil", password="pass123")

    def test_light_mode(self):
        """Light mode returns light theme name."""
        self.user.profile.theme_mode = "light"
        self.user.profile.theme_name = "cupcake"
        self.user.profile.save()
        self.assertEqual(get_effective_theme(self.user), "cupcake")

    def test_dark_mode(self):
        """Dark mode returns dark theme name."""
        self.user.profile.theme_mode = "dark"
        self.user.profile.dark_theme_name = "night"
        self.user.profile.save()
        self.assertEqual(get_effective_theme(self.user), "night")

    def test_auto_mode_returns_light(self):
        """Auto mode returns light theme (JS handles system detection)."""
        self.user.profile.theme_mode = "auto"
        self.user.profile.theme_name = "corporate"
        self.user.profile.save()
        self.assertEqual(get_effective_theme(self.user), "corporate")

    def test_no_profile_fallback(self):
        """Falls back to corporate for user without profile."""
        user_no_profile = MagicMock(spec=[])
        self.assertEqual(get_effective_theme(user_no_profile), "corporate")
