"""Unit tests for config logic (module-level helpers) and config read/write via HTTP."""

import json
import pytest
import routes


# ── _migrate_custom_tuning ────────────────────────────────────────────────────

class TestMigrateCustomTuning:
    def test_old_flat_list_guitar6(self):
        result = routes._migrate_custom_tuning("My Tuning", [82.41, 110.00, 146.83, 196.00, 246.94, 329.63])
        assert result == {"instrument": "guitar-6", "strings": [82.41, 110.00, 146.83, 196.00, 246.94, 329.63]}

    def test_old_flat_list_bass4(self):
        result = routes._migrate_custom_tuning("Drop D Bass", [36.71, 55.00, 73.42, 98.00])
        assert result["instrument"] == "bass-4"
        assert result["strings"] == [36.71, 55.00, 73.42, 98.00]

    def test_old_flat_list_bass5(self):
        result = routes._migrate_custom_tuning("5-String", [30.87, 41.20, 55.00, 73.42, 98.00])
        assert result["instrument"] == "bass-5"

    def test_old_flat_list_guitar7(self):
        result = routes._migrate_custom_tuning("7-String", [61.74, 82.41, 110.00, 146.83, 196.00, 246.94, 329.63])
        assert result["instrument"] == "guitar-7"

    def test_old_flat_list_guitar8(self):
        strings = [46.25, 61.74, 82.41, 110.00, 146.83, 196.00, 246.94, 329.63]
        result = routes._migrate_custom_tuning("8-String", strings)
        assert result["instrument"] == "guitar-8"

    def test_old_flat_list_unknown_count_defaults_guitar6(self):
        result = routes._migrate_custom_tuning("3-String", [100.0, 200.0, 300.0])
        assert result["instrument"] == "guitar-6"

    def test_new_dict_format_passthrough(self):
        value = {"instrument": "bass-4", "strings": [41.20, 55.00, 73.42, 98.00]}
        result = routes._migrate_custom_tuning("My Bass", value)
        assert result == value

    def test_malformed_dict_returns_empty_guitar6(self):
        result = routes._migrate_custom_tuning("Bad", {"foo": "bar"})
        assert result == {"instrument": "guitar-6", "strings": []}


# ── Config read/write via HTTP ────────────────────────────────────────────────

class TestConfigDefaults:
    def test_get_returns_all_default_keys(self, client):
        r = client.get("/api/plugins/tuner/config")
        assert r.status_code == 200
        body = r.json()
        assert body["lastTuning"] == "Standard"
        assert body["lastInstrument"] == "guitar-6"
        assert body["audioInputMode"] == "auto"
        assert body["showFloatingButton"] is True
        assert body["visualizationMode"] == "default"
        assert body["customTunings"] == {}
        assert body["disabledTunings"] == []

    def test_get_does_not_include_default_tunings(self, client):
        # defaultTunings moved to GET /api/tunings (core tuning.read capability).
        body = client.get("/api/plugins/tuner/config").json()
        assert "defaultTunings" not in body


class TestConfigPersistence:
    def test_partial_update_persisted(self, client):
        client.post("/api/plugins/tuner/config", json={"lastTuning": "Drop D"})
        r = client.get("/api/plugins/tuner/config")
        assert r.json()["lastTuning"] == "Drop D"

    def test_unmodified_fields_survive_partial_update(self, client):
        client.post("/api/plugins/tuner/config", json={"lastTuning": "Drop D"})
        client.post("/api/plugins/tuner/config", json={"visualizationMode": "strobe"})
        body = client.get("/api/plugins/tuner/config").json()
        assert body["lastTuning"] == "Drop D"
        assert body["visualizationMode"] == "strobe"

    def test_default_tunings_not_written_to_file(self, client, config_dir):
        client.post("/api/plugins/tuner/config", json={
            "lastTuning": "Open G",
            "defaultTunings": {"guitar-6": {"Standard": []}},
        })
        saved = json.loads((config_dir / "tuner.json").read_text())
        assert "defaultTunings" not in saved

    def test_invalid_audio_mode_resets_to_auto(self, client):
        client.post("/api/plugins/tuner/config", json={"audioInputMode": "invalid"})
        body = client.get("/api/plugins/tuner/config").json()
        assert body["audioInputMode"] == "auto"

    def test_valid_audio_mode_browser_accepted(self, client):
        client.post("/api/plugins/tuner/config", json={"audioInputMode": "browser"})
        assert client.get("/api/plugins/tuner/config").json()["audioInputMode"] == "browser"

    def test_disabled_tunings_strips_entries_without_colon(self, client):
        client.post("/api/plugins/tuner/config", json={
            "disabledTunings": ["guitar-6:Drop D", "legacy-entry", "bass-4:Standard"]
        })
        body = client.get("/api/plugins/tuner/config").json()
        assert "legacy-entry" not in body["disabledTunings"]
        assert "guitar-6:Drop D" in body["disabledTunings"]
        assert "bass-4:Standard" in body["disabledTunings"]

    def test_custom_tuning_old_format_migrated_on_read(self, client, config_dir):
        (config_dir / "tuner.json").write_text(json.dumps({
            "customTunings": {"My Tuning": [82.41, 110.0, 146.83, 196.0, 246.94, 329.63]}
        }))
        body = client.get("/api/plugins/tuner/config").json()
        assert body["customTunings"]["My Tuning"]["instrument"] == "guitar-6"
        assert isinstance(body["customTunings"]["My Tuning"]["strings"], list)

    def test_malformed_config_file_returns_defaults(self, client, config_dir):
        (config_dir / "tuner.json").write_text("not json at all {{")
        r = client.get("/api/plugins/tuner/config")
        assert r.status_code == 200
        assert r.json()["lastTuning"] == "Standard"


# ── referencePitch — now a core setting, not a tuner config field ─────────────
# referencePitch moved to GET/POST /api/settings (core tuning.read capability).
# The tuner config must not expose or persist it.

class TestReferencePitchNotInTunerConfig:
    def test_not_present_in_default_response(self, client):
        body = client.get("/api/plugins/tuner/config").json()
        assert "referencePitch" not in body

    def test_posting_reference_pitch_is_ignored(self, client):
        # POSTing referencePitch must not break the request or leak the field back.
        r = client.post("/api/plugins/tuner/config", json={"referencePitch": 432, "lastTuning": "Drop D"})
        assert r.status_code == 200
        body = client.get("/api/plugins/tuner/config").json()
        assert "referencePitch" not in body
        assert body["lastTuning"] == "Drop D"

    def test_reference_pitch_not_written_to_file(self, client, config_dir):
        client.post("/api/plugins/tuner/config", json={"referencePitch": 443})
        saved = json.loads((config_dir / "tuner.json").read_text())
        assert "referencePitch" not in saved
