"""
Settings — monthly income tests — Story 4.1.
"""
from decimal import Decimal

import pytest

from app.extensions import db as _db
from app.models.settings import Settings


# ── GET ───────────────────────────────────────────────────────────────────────

class TestIncomeGet:
    def test_returns_200(self, client, db):
        response = client.get('/settings/income')
        assert response.status_code == 200

    def test_shows_income_form(self, client, db):
        response = client.get('/settings/income')
        assert b'monthly_income' in response.data or b'Income' in response.data

    def test_shows_blank_when_not_set(self, client, db):
        response = client.get('/settings/income')
        # No settings row yet — form should render (not crash)
        assert response.status_code == 200

    def test_shows_existing_income_prefilled(self, client, db):
        s = Settings(id=1, monthly_income=Decimal('4500.00'))
        _db.session.add(s)
        _db.session.commit()
        response = client.get('/settings/income')
        assert b'4500' in response.data


# ── POST valid ────────────────────────────────────────────────────────────────

class TestIncomePostValid:
    def test_valid_post_redirects(self, client, db):
        response = client.post('/settings/income',
                               data={'monthly_income': '5000.00'},
                               follow_redirects=False)
        assert response.status_code == 302

    def test_redirect_target_is_income_page(self, client, db):
        response = client.post('/settings/income',
                               data={'monthly_income': '5000.00'},
                               follow_redirects=False)
        assert '/settings/income' in response.headers['Location']

    def test_valid_post_saves_value(self, client, db):
        client.post('/settings/income', data={'monthly_income': '5000.00'})
        s = Settings.query.first()
        assert s is not None
        assert s.monthly_income == Decimal('5000.00')

    def test_valid_post_flashes_success(self, client, db):
        response = client.post('/settings/income',
                               data={'monthly_income': '5000.00'},
                               follow_redirects=True)
        assert b'updated' in response.data.lower()

    def test_updates_existing_row_not_creates_new(self, client, db):
        s = Settings(id=1, monthly_income=Decimal('3000.00'))
        _db.session.add(s)
        _db.session.commit()
        client.post('/settings/income', data={'monthly_income': '4000.00'})
        assert Settings.query.count() == 1
        _db.session.refresh(s)
        assert s.monthly_income == Decimal('4000.00')

    def test_zero_income_accepted(self, client, db):
        response = client.post('/settings/income',
                               data={'monthly_income': '0'},
                               follow_redirects=False)
        assert response.status_code == 302
        s = Settings.query.first()
        assert s.monthly_income == Decimal('0')

    def test_decimal_precision_stored(self, client, db):
        client.post('/settings/income', data={'monthly_income': '4567.89'})
        s = Settings.query.first()
        assert s.monthly_income == Decimal('4567.89')


# ── POST invalid ──────────────────────────────────────────────────────────────

class TestIncomePostInvalid:
    def test_non_numeric_rerenders_form(self, client, db):
        response = client.post('/settings/income',
                               data={'monthly_income': 'not-a-number'})
        assert response.status_code == 200

    def test_non_numeric_shows_error(self, client, db):
        response = client.post('/settings/income',
                               data={'monthly_income': 'abc'})
        assert b'valid' in response.data.lower() or b'numeric' in response.data.lower() or b'number' in response.data.lower()

    def test_negative_value_rejected(self, client, db):
        response = client.post('/settings/income',
                               data={'monthly_income': '-100'})
        assert response.status_code == 200

    def test_negative_value_shows_error(self, client, db):
        response = client.post('/settings/income',
                               data={'monthly_income': '-100'})
        assert b'zero or greater' in response.data.lower() or b'negative' in response.data.lower()

    def test_negative_does_not_save(self, client, db):
        client.post('/settings/income', data={'monthly_income': '-100'})
        assert Settings.query.first() is None

    def test_empty_string_rerenders_form(self, client, db):
        response = client.post('/settings/income', data={'monthly_income': ''})
        assert response.status_code == 200


# ── Settings index ────────────────────────────────────────────────────────────

class TestSettingsIndex:
    def test_index_shows_income_link(self, client, db):
        response = client.get('/settings/')
        assert b'/settings/income' in response.data

    def test_index_shows_current_income_when_set(self, client, db):
        s = Settings(id=1, monthly_income=Decimal('6000.00'))
        _db.session.add(s)
        _db.session.commit()
        response = client.get('/settings/')
        assert b'6000' in response.data

    def test_index_shows_not_set_when_no_income(self, client, db):
        response = client.get('/settings/')
        assert b'not set' in response.data.lower() or b'Not set' in response.data
