"""Counterexamples for synthetic classification rules; not field evaluation."""
import copy
import json
from pathlib import Path
import unittest
from observation_evidence import classify

CUTOFF = '2026-01-15T10:00:00Z'
RECORD = dict(asset='fictional-A', value=0, observed_at='2026-01-15T09:55:00Z', received_at='2026-01-15T09:56:00Z', time_origin='observed', quality='accepted')


class ObservationEvidenceTests(unittest.TestCase):
    def result(self, **changes):
        row = {**RECORD, **changes}
        return classify(row, CUTOFF, 900)

    def test_fixed_fixture(self):
        f = json.loads(Path(__file__).with_name('synthetic-observations.json').read_text())
        for c in f['cases']:
            with self.subTest(case=c['case']):
                self.assertEqual(classify(c['record'], f['as_of'], f['max_age_seconds'])['state'], c['expected_state'])

    def test_zero_is_current_value(self):
        self.assertEqual(self.result()['value'], 0)
        self.assertTrue(self.result()['usable_for_current_decision'])

    def test_missing_is_not_zero(self):
        r = classify(None, CUTOFF, 900)
        self.assertIsNone(r['value'])
        self.assertFalse(r['usable_for_current_decision'])

    def test_recent_arrival_cannot_refresh_old_observation(self):
        self.assertEqual(self.result(observed_at='2026-01-15T09:00:00Z', received_at='2026-01-15T09:59:00Z')['state'], 'stale')

    def test_cutoff_excludes_later_receipt(self):
        self.assertEqual(self.result(received_at='2026-01-15T10:00:01Z')['state'], 'not_yet_received')

    def test_at_cutoff_is_visible(self):
        self.assertEqual(self.result(received_at=CUTOFF)['state'], 'current')

    def test_exact_age_boundary(self):
        self.assertEqual(self.result(observed_at='2026-01-15T09:45:00Z')['state'], 'current')
        self.assertEqual(self.result(observed_at='2026-01-15T09:44:59Z')['state'], 'stale')

    def test_unknown_origin_does_not_inherit_server_time(self):
        self.assertEqual(self.result(time_origin='unknown')['state'], 'unknown_time')

    def test_suspect_is_ineligible_even_when_recent(self):
        self.assertFalse(self.result(quality='suspect')['usable_for_current_decision'])
        self.assertEqual(self.result(quality='suspect')['state'], 'suspect')

    def test_precedence_retains_cutoff_and_unknown_time(self):
        self.assertEqual(self.result(time_origin='unknown', quality='suspect', received_at='2026-01-15T10:01:00Z')['state'], 'not_yet_received')
        self.assertEqual(self.result(time_origin='unknown', quality='suspect')['state'], 'unknown_time')

    def test_bad_values_rejected(self):
        for x in [None, True, '0', -1, 101, 10**400, float('nan'), float('inf')]:
            with self.subTest(value=x), self.assertRaises(ValueError): self.result(value=x)

    def test_time_contract_rejects_naive_missing_and_impossible(self):
        for changes in [dict(observed_at='2026-01-15T09:55:00'),dict(observed_at=None),dict(observed_at='2026-01-15T10:01:00Z'),dict(received_at='bad')]:
            with self.subTest(changes=changes), self.assertRaises(ValueError): self.result(**changes)

    def test_offsets_describe_same_instant(self):
        self.assertEqual(self.result(observed_at='2026-01-15T13:55:00+04:00'), self.result())

    def test_invalid_contract_and_input_preservation(self):
        for x in [0, -1, True, float('inf')]:
            with self.subTest(limit=x), self.assertRaises(ValueError): classify(RECORD,CUTOFF,x)
        self.assertEqual(classify(RECORD,CUTOFF,10**400)['state'],'current')
        r=copy.deepcopy(RECORD)
        classify(r,CUTOFF,900)
        self.assertEqual(r,RECORD)
        for changes in [dict(quality='good'),dict(time_origin='defaulted'),dict(asset='')]:
            with self.subTest(changes=changes), self.assertRaises(ValueError): self.result(**changes)


if __name__ == '__main__':
    unittest.main()
