"""Tests for queue.json validation and backup in triage_score.py."""

from __future__ import annotations

import json

import pytest
import scripts.triage_score as ts


@pytest.fixture(autouse=True)
def _isolate(tmp_path, monkeypatch):
    """Redirect triage_score paths to tmp_path for isolation."""
    monkeypatch.setattr(ts, "QUEUE_FILE", tmp_path / "queue.json")
    monkeypatch.setattr(ts, "QUEUE_BACKUP_FILE", tmp_path / "queue.json.bak")
    monkeypatch.setattr(ts, "RETRO_FILE", tmp_path / "retro" / "triage.jsonl")
    monkeypatch.setattr(ts, "QUARANTINE_FILE", tmp_path / "quarantine.json")
    monkeypatch.setattr(ts, "CYCLE_RETRO_FILE", tmp_path / "retro" / "cycles.jsonl")


def test_backup_created_on_write(tmp_path):
    """When writing queue.json, a backup should be created from previous valid file."""
    # Create initial valid queue file
    initial_data = [{"issue": 1, "title": "Test", "ready": True}]
    ts.QUEUE_FILE.parent.mkdir(parents=True, exist_ok=True)
    ts.QUEUE_FILE.write_text(json.dumps(initial_data))

    # Write new data
    new_data = [{"issue": 2, "title": "New", "ready": True}]
    ts.QUEUE_FILE.write_text(json.dumps(new_data, indent=2) + "\n")

    # Manually run the backup logic as run_triage would
    if ts.QUEUE_FILE.exists():
        try:
            json.loads(ts.QUEUE_FILE.read_text())
            ts.QUEUE_BACKUP_FILE.write_text(ts.QUEUE_FILE.read_text())
        except (json.JSONDecodeError, OSError):
            pass

    # Both files should exist with same content
    assert ts.QUEUE_BACKUP_FILE.exists()
    assert json.loads(ts.QUEUE_BACKUP_FILE.read_text()) == new_data


def test_corrupt_queue_restored_from_backup(tmp_path, capsys):
    """If queue.json is corrupt, it should be restored from backup."""
    # Create a valid backup
    valid_data = [{"issue": 1, "title": "Backup", "ready": True}]
    ts.QUEUE_BACKUP_FILE.parent.mkdir(parents=True, exist_ok=True)
    ts.QUEUE_BACKUP_FILE.write_text(json.dumps(valid_data, indent=2) + "\n")

    # Create a corrupt queue file
    ts.QUEUE_FILE.parent.mkdir(parents=True, exist_ok=True)
    ts.QUEUE_FILE.write_text("not valid json {{{")

    # Run validation and restore logic
    try:
        json.loads(ts.QUEUE_FILE.read_text())
    except (json.JSONDecodeError, OSError):
        if ts.QUEUE_BACKUP_FILE.exists():
            try:
                backup_data = ts.QUEUE_BACKUP_FILE.read_text()
                json.loads(backup_data)  # Validate backup
                ts.QUEUE_FILE.write_text(backup_data)
                print("[triage] Restored queue.json from backup")
            except (json.JSONDecodeError, OSError):
                ts.QUEUE_FILE.write_text("[]\n")
        else:
            ts.QUEUE_FILE.write_text("[]\n")

    # Queue should be restored from backup
    assert json.loads(ts.QUEUE_FILE.read_text()) == valid_data
    captured = capsys.readouterr()
    assert "Restored queue.json from backup" in captured.out


def test_corrupt_queue_no_backup_writes_empty_list(tmp_path):
    """If queue.json is corrupt and no backup exists, write empty list."""
    # Ensure no backup exists
    assert not ts.QUEUE_BACKUP_FILE.exists()

    # Create a corrupt queue file
    ts.QUEUE_FILE.parent.mkdir(parents=True, exist_ok=True)
    ts.QUEUE_FILE.write_text("not valid json {{{")

    # Run validation and restore logic
    try:
        json.loads(ts.QUEUE_FILE.read_text())
    except (json.JSONDecodeError, OSError):
        if ts.QUEUE_BACKUP_FILE.exists():
            try:
                backup_data = ts.QUEUE_BACKUP_FILE.read_text()
                json.loads(backup_data)
                ts.QUEUE_FILE.write_text(backup_data)
            except (json.JSONDecodeError, OSError):
                ts.QUEUE_FILE.write_text("[]\n")
        else:
            ts.QUEUE_FILE.write_text("[]\n")

    # Should have empty list
    assert json.loads(ts.QUEUE_FILE.read_text()) == []


def test_corrupt_backup_writes_empty_list(tmp_path):
    """If both queue.json and backup are corrupt, write empty list."""
    # Create a corrupt backup
    ts.QUEUE_BACKUP_FILE.parent.mkdir(parents=True, exist_ok=True)
    ts.QUEUE_BACKUP_FILE.write_text("also corrupt backup")

    # Create a corrupt queue file
    ts.QUEUE_FILE.parent.mkdir(parents=True, exist_ok=True)
    ts.QUEUE_FILE.write_text("not valid json {{{")

    # Run validation and restore logic
    try:
        json.loads(ts.QUEUE_FILE.read_text())
    except (json.JSONDecodeError, OSError):
        if ts.QUEUE_BACKUP_FILE.exists():
            try:
                backup_data = ts.QUEUE_BACKUP_FILE.read_text()
                json.loads(backup_data)
                ts.QUEUE_FILE.write_text(backup_data)
            except (json.JSONDecodeError, OSError):
                ts.QUEUE_FILE.write_text("[]\n")
        else:
            ts.QUEUE_FILE.write_text("[]\n")

    # Should have empty list
    assert json.loads(ts.QUEUE_FILE.read_text()) == []


def test_valid_queue_not_corrupt_no_backup_overwrite(tmp_path):
    """Don't overwrite backup if current queue.json is corrupt."""
    # Create a valid backup
    valid_backup = [{"issue": 99, "title": "Old Backup", "ready": True}]
    ts.QUEUE_BACKUP_FILE.parent.mkdir(parents=True, exist_ok=True)
    ts.QUEUE_BACKUP_FILE.write_text(json.dumps(valid_backup, indent=2) + "\n")

    # Create a corrupt queue file
    ts.QUEUE_FILE.parent.mkdir(parents=True, exist_ok=True)
    ts.QUEUE_FILE.write_text("corrupt data")

    # Try to save backup (should skip because current is corrupt)
    if ts.QUEUE_FILE.exists():
        try:
            json.loads(ts.QUEUE_FILE.read_text())  # This will fail
            ts.QUEUE_BACKUP_FILE.write_text(ts.QUEUE_FILE.read_text())
        except (json.JSONDecodeError, OSError):
            pass  # Should hit this branch

    # Backup should still have original valid data
    assert json.loads(ts.QUEUE_BACKUP_FILE.read_text()) == valid_backup


def test_backup_path_configuration():
    """Ensure backup file path is properly configured relative to queue file."""
    assert ts.QUEUE_BACKUP_FILE.parent == ts.QUEUE_FILE.parent
    assert ts.QUEUE_BACKUP_FILE.name == "queue.json.bak"
    assert ts.QUEUE_FILE.name == "queue.json"
