"""
Unit tests for the populate_ephemeris management command.

pyswisseph calls are mocked — these tests verify date iteration,
snapshot persistence, and idempotency without touching the ephemeris.

Run:
    pyswiss/.venv/Scripts/python pyswiss/manage.py test pyswiss/apps/charts
"""
from datetime import datetime, timezone
from unittest.mock import patch

from django.core.management import call_command
from django.test import TestCase

from apps.charts.models import EphemerisSnapshot


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

# 10 planets covering Fire×3, Earth×3, Air×2, Water×2 (one per sign)
# Expected: fire=3, water=2, earth=3, air=2, time=0, space=9
FAKE_PLANETS = {
    'Sun':     {'sign': 'Aries',       'degree': 10.0,  'retrograde': False},
    'Moon':    {'sign': 'Leo',          'degree': 130.0, 'retrograde': False},
    'Mercury': {'sign': 'Sagittarius',  'degree': 250.0, 'retrograde': False},
    'Venus':   {'sign': 'Taurus',       'degree': 40.0,  'retrograde': False},
    'Mars':    {'sign': 'Virgo',        'degree': 160.0, 'retrograde': False},
    'Jupiter': {'sign': 'Capricorn',    'degree': 280.0, 'retrograde': False},
    'Saturn':  {'sign': 'Gemini',       'degree': 70.0,  'retrograde': False},
    'Uranus':  {'sign': 'Aquarius',     'degree': 310.0, 'retrograde': False},
    'Neptune': {'sign': 'Cancer',       'degree': 100.0, 'retrograde': False},
    'Pluto':   {'sign': 'Pisces',       'degree': 340.0, 'retrograde': False},
}

PATCH_TARGET = (
    'apps.charts.management.commands.populate_ephemeris.get_planet_positions'
)


# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------

class PopulateEphemerisCommandTest(TestCase):

    def _run(self, date_from, date_to):
        with patch(PATCH_TARGET, return_value=FAKE_PLANETS):
            call_command('populate_ephemeris',
                         date_from=date_from, date_to=date_to,
                         verbosity=0)

    # ── date iteration ────────────────────────────────────────────────────

    def test_creates_one_snapshot_per_day(self):
        self._run('2000-01-01', '2000-01-03')
        self.assertEqual(EphemerisSnapshot.objects.count(), 3)

    def test_single_day_range_creates_one_snapshot(self):
        self._run('2000-01-01', '2000-01-01')
        self.assertEqual(EphemerisSnapshot.objects.count(), 1)

    def test_snapshots_are_at_noon_utc(self):
        self._run('2000-01-01', '2000-01-01')
        snap = EphemerisSnapshot.objects.get()
        self.assertEqual(snap.dt, datetime(2000, 1, 1, 12, 0, 0, tzinfo=timezone.utc))

    # ── idempotency ───────────────────────────────────────────────────────

    def test_rerunning_does_not_create_duplicates(self):
        self._run('2000-01-01', '2000-01-03')
        self._run('2000-01-01', '2000-01-03')
        self.assertEqual(EphemerisSnapshot.objects.count(), 3)

    def test_overlapping_ranges_do_not_duplicate(self):
        self._run('2000-01-01', '2000-01-03')
        self._run('2000-01-02', '2000-01-05')
        self.assertEqual(EphemerisSnapshot.objects.count(), 5)

    # ── element counts ────────────────────────────────────────────────────

    def test_element_counts_are_persisted(self):
        self._run('2000-01-01', '2000-01-01')
        snap = EphemerisSnapshot.objects.get()
        self.assertEqual(snap.fire,  3)
        self.assertEqual(snap.water, 2)
        self.assertEqual(snap.earth, 3)
        self.assertEqual(snap.air,   2)
        self.assertEqual(snap.time_el,  0)
        self.assertEqual(snap.space_el, 9)

    # ── chart_data payload ────────────────────────────────────────────────

    def test_chart_data_contains_planets(self):
        self._run('2000-01-01', '2000-01-01')
        snap = EphemerisSnapshot.objects.get()
        self.assertEqual(snap.chart_data['planets'], FAKE_PLANETS)
