"""Scheduled passes discover newly granted resets despite an old usage summary."""

import json
import os
import subprocess
import time
import unittest

import test_codex_reset as fixtures


class ResetPollingTest(fixtures.CodexPoolSandbox, unittest.TestCase):
    def setUp(self):
        super().setUp()
        now = int(time.time())
        self.server.state["usage"] = {"rate_limit": {"allowed": False, "limit_reached": True,
            "primary_window": {"used_percent": 100, "limit_window_seconds": 604800,
                               "reset_at": now + 6 * 86400}},
            "rate_limit_reset_credits": {"available_count": 0}}
        self.server.state["credits"] = {"available_count": 0, "credits": []}

    def run_scheduled(self, enabled="1"):
        base = f"http://127.0.0.1:{self.server.server_port}/wham"
        env = dict(os.environ, CODEX_ACCOUNTS_ROOT=str(self.pool), CODEX_MULTIACC_NO_SYNC="1",
                   CODEX_MULTIACC_AUTO_RESET=enabled, CODEX_MULTIACC_USAGE_URL=f"{base}/usage",
                   PYTHONDONTWRITEBYTECODE="1")
        for key in ("CODEX_MULTIACC_MIN_FETCH", "CODEX_MULTIACC_RESET_CREDITS_URL",
                    "CODEX_MULTIACC_RESET_CONSUME_URL"):
            env.pop(key, None)
        result = subprocess.run([fixtures.REPO / "bin/codex-accounts", "limits", "--quiet"],
                                capture_output=True, text=True, env=env, timeout=20, check=False)
        self.assertEqual(result.returncode, 0, result.stderr)

    def next_pass(self):
        path = self.pool / "acct-01/limits.json"
        usage = json.loads(path.read_text())
        usage["fetched_at"] = int(time.time()) - 301
        path.write_text(json.dumps(usage))

    def grant_credit(self):
        self.server.state["credits"] = {"available_count": 1, "credits": [
            {"id": "newly-granted", "status": "available", "expires_at": "2099-01-01T00:00:00Z"}]}
        self.server.state["responses"] = [(200, {"code": "reset", "windows_reset": 1})]

    def test_limited_account_polls_again_and_uses_a_new_credit(self):
        self.run_scheduled()
        self.assertEqual(self.server.state["credit_gets"], 1)
        marker = self.pool / "acct-01/.limited"
        self.assertTrue(marker.exists())
        self.assertEqual(self.server.state["posts"], [])
        self.run_scheduled()
        self.assertEqual(self.server.state["credit_gets"], 1)  # Normal fetch cadence still applies.
        self.next_pass()
        self.run_scheduled()
        self.assertEqual(self.server.state["credit_gets"], 2)
        self.assertTrue(marker.exists())
        self.grant_credit()
        self.next_pass()
        self.run_scheduled()
        self.assertEqual(self.server.state["credit_gets"], 4)
        self.assertEqual(self.server.state["posts"][0]["credit_id"], "newly-granted")
        self.assertFalse(marker.exists())
        receipt = json.loads((self.pool / "acct-01/.usage-reset.json").read_text())
        self.assertEqual(receipt["state"], "complete")
        usage = json.loads((self.pool / "acct-01/limits.json").read_text())
        self.assertEqual(usage["fetched_at"], 0)  # Pre-reset exhaustion cannot exclude it again.

    def test_malformed_usage_summary_does_not_hide_a_credit(self):
        self.server.state["usage"]["rate_limit_reset_credits"]["available_count"] = "unknown"
        self.grant_credit()
        self.run_scheduled()
        self.assertEqual(len(self.server.state["posts"]), 1)

    def test_credit_lookup_failure_preserves_limit_and_retries_next_pass(self):
        self.server.state["credits"] = []  # An unreadable credit response is not a reset.
        self.run_scheduled()
        self.assertTrue((self.pool / "acct-01/.limited").exists())
        self.assertEqual(self.server.state["posts"], [])
        self.grant_credit()
        self.next_pass()
        self.run_scheduled()
        self.assertEqual(self.server.state["credit_gets"], 3)
        self.assertFalse((self.pool / "acct-01/.limited").exists())

    def test_disabled_automation_reports_without_spending_credits(self):
        self.grant_credit()
        self.run_scheduled(enabled="0")
        self.assertEqual(self.server.state["credit_gets"], 1)
        self.assertEqual(self.server.state["posts"], [])
        self.assertTrue((self.pool / "acct-01/.limited").exists())


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