"""
Integration tests for GET /api/charts/ — ephemeris range/filter queries.

These tests drive the EphemerisSnapshot model and list view.
Snapshots are created directly in setUp — no live ephemeris calc needed.

Run:
    pyswiss/.venv/Scripts/python pyswiss/manage.py test pyswiss/apps/charts
"""
from django.test import TestCase

from apps.charts.models import EphemerisSnapshot


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

CHART_DATA_STUB = {
    'planets': {
        'Sun':     {'sign': 'Capricorn', 'degree': 280.37, 'retrograde': False},
        'Moon':    {'sign': 'Aries',     'degree': 15.2,   'retrograde': False},
        'Mercury': {'sign': 'Capricorn', 'degree': 275.1,  'retrograde': False},
        'Venus':   {'sign': 'Sagittarius','degree': 250.3, 'retrograde': False},
        'Mars':    {'sign': 'Aquarius',  'degree': 308.6,  'retrograde': False},
        'Jupiter': {'sign': 'Aries',     'degree': 25.9,   'retrograde': False},
        'Saturn':  {'sign': 'Taurus',    'degree': 40.5,   'retrograde': False},
        'Uranus':  {'sign': 'Aquarius',  'degree': 314.2,  'retrograde': False},
        'Neptune': {'sign': 'Capricorn', 'degree': 303.8,  'retrograde': False},
        'Pluto':   {'sign': 'Sagittarius','degree': 248.4, 'retrograde': False},
    },
    'houses': {'cusps': [0]*12, 'asc': 180.0, 'mc': 90.0},
}


def make_snapshot(dt_str, fire=2, water=2, earth=3, air=2, time_el=1, space_el=3,
                  chart_data=None):
    return EphemerisSnapshot.objects.create(
        dt=dt_str,
        fire=fire, water=water, earth=earth, air=air,
        time_el=time_el, space_el=space_el,
        chart_data=chart_data or CHART_DATA_STUB,
    )


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

class ChartsListApiTest(TestCase):
    """GET /api/charts/ — query pre-computed ephemeris snapshots."""

    def setUp(self):
        make_snapshot('2000-01-01T12:00:00Z', fire=3, water=2, earth=3, air=2)
        make_snapshot('2000-01-02T12:00:00Z', fire=1, water=4, earth=3, air=2)
        make_snapshot('2000-01-03T12:00:00Z', fire=2, water=2, earth=4, air=2)
        # Outside the usual date range — should not appear in filtered results
        make_snapshot('2001-06-15T12:00:00Z', fire=4, water=1, earth=3, air=2)

    def _get(self, params=None):
        return self.client.get('/api/charts/', params or {})

    # ── guards ────────────────────────────────────────────────────────────

    def test_charts_returns_400_if_date_from_missing(self):
        response = self._get({'date_to': '2000-01-31'})
        self.assertEqual(response.status_code, 400)

    def test_charts_returns_400_if_date_to_missing(self):
        response = self._get({'date_from': '2000-01-01'})
        self.assertEqual(response.status_code, 400)

    def test_charts_returns_400_for_invalid_date_from(self):
        response = self._get({'date_from': 'not-a-date', 'date_to': '2000-01-31'})
        self.assertEqual(response.status_code, 400)

    def test_charts_returns_400_if_date_to_before_date_from(self):
        response = self._get({'date_from': '2000-01-31', 'date_to': '2000-01-01'})
        self.assertEqual(response.status_code, 400)

    # ── response shape ────────────────────────────────────────────────────

    def test_charts_returns_200_for_valid_params(self):
        response = self._get({'date_from': '2000-01-01', 'date_to': '2000-01-31'})
        self.assertEqual(response.status_code, 200)

    def test_charts_response_is_json(self):
        response = self._get({'date_from': '2000-01-01', 'date_to': '2000-01-31'})
        self.assertIn('application/json', response['Content-Type'])

    def test_charts_response_has_results_and_count(self):
        data = self._get({'date_from': '2000-01-01', 'date_to': '2000-01-31'}).json()
        self.assertIn('results', data)
        self.assertIn('count', data)

    def test_each_result_has_dt_and_elements(self):
        data = self._get({'date_from': '2000-01-01', 'date_to': '2000-01-31'}).json()
        for result in data['results']:
            with self.subTest(dt=result.get('dt')):
                self.assertIn('dt', result)
                self.assertIn('elements', result)
                for key in ('Fire', 'Water', 'Earth', 'Air', 'Time', 'Space'):
                    self.assertIn(key, result['elements'])

    def test_each_result_has_planets(self):
        data = self._get({'date_from': '2000-01-01', 'date_to': '2000-01-31'}).json()
        for result in data['results']:
            with self.subTest(dt=result.get('dt')):
                self.assertIn('planets', result)

    # ── date range filtering ──────────────────────────────────────────────

    def test_charts_returns_only_snapshots_in_date_range(self):
        data = self._get({'date_from': '2000-01-01', 'date_to': '2000-01-31'}).json()
        self.assertEqual(data['count'], 3)

    def test_charts_count_matches_results_length(self):
        data = self._get({'date_from': '2000-01-01', 'date_to': '2000-12-31'}).json()
        self.assertEqual(data['count'], len(data['results']))

    def test_charts_date_range_is_inclusive(self):
        data = self._get({'date_from': '2000-01-01', 'date_to': '2000-01-01'}).json()
        self.assertEqual(data['count'], 1)

    def test_charts_results_ordered_by_dt(self):
        data = self._get({'date_from': '2000-01-01', 'date_to': '2000-01-31'}).json()
        dts = [r['dt'] for r in data['results']]
        self.assertEqual(dts, sorted(dts))

    # ── element range filtering ───────────────────────────────────────────

    def test_charts_filters_by_fire_min(self):
        # Only the Jan 1 snapshot has fire=3; Jan 2 has fire=1, Jan 3 has fire=2
        data = self._get({
            'date_from': '2000-01-01', 'date_to': '2000-01-31', 'fire_min': 3,
        }).json()
        self.assertEqual(data['count'], 1)

    def test_charts_filters_by_water_min(self):
        # Only the Jan 2 snapshot has water=4
        data = self._get({
            'date_from': '2000-01-01', 'date_to': '2000-01-31', 'water_min': 4,
        }).json()
        self.assertEqual(data['count'], 1)

    def test_charts_filters_by_earth_min(self):
        # Jan 3 has earth=4; Jan 1 and Jan 2 have earth=3
        data = self._get({
            'date_from': '2000-01-01', 'date_to': '2000-01-31', 'earth_min': 4,
        }).json()
        self.assertEqual(data['count'], 1)

    def test_charts_multiple_element_filters_are_conjunctive(self):
        # fire>=2 AND water>=2: Jan 1 (fire=3,water=2) + Jan 3 (fire=2,water=2); not Jan 2 (fire=1)
        data = self._get({
            'date_from': '2000-01-01', 'date_to': '2000-01-31',
            'fire_min': 2, 'water_min': 2,
        }).json()
        self.assertEqual(data['count'], 2)
