import os
import subprocess
import sys
import pytest
from gilas import pvar

def _run_list_script(db_path, values):
    script = (
        "from gilas import plist\n"
        "arr = plist('numbers')\n"
        "for v in {values}:\n"
        "    arr.append(v)\n"
        "print(list(arr))\n"
    ).format(values=values)
    env = os.environ.copy()
    env["GILAS_DB_PATH"] = str(db_path)
    result = subprocess.run(
        [sys.executable, "-c", script],
        env=env,
        check=True,
        capture_output=True,
        text=True,
    )
    return result.stdout.strip()


def _run_dict_script(db_path, payload, delete_keys=None, set_default=None):
    delete_keys = delete_keys or []
    set_default = set_default or {}
    script = (
        "from gilas import pdict\n"
        "data = pdict('settings')\n"
        "data.update({payload})\n"
        "for k, v in {set_default}.items():\n"
        "    data.setdefault(k, v)\n"
        "for k in {delete_keys}:\n"
        "    data.pop(k, None)\n"
        "print(sorted(dict(data).items()))\n"
    ).format(payload=payload, delete_keys=delete_keys, set_default=set_default)
    env = os.environ.copy()
    env["GILAS_DB_PATH"] = str(db_path)
    result = subprocess.run(
        [sys.executable, "-c", script],
        env=env,
        check=True,
        capture_output=True,
        text=True,
    )
    return result.stdout.strip()

def _run_var_script(db_path, value=None, set_value=False):
    script = (
        "from gilas import pvar\n"
        "v = pvar('counter')\n"
    )
    if set_value:
        script += "v.value = {value}\n".format(value=value)
    script += "print(v.value)\n"

    env = os.environ.copy()
    env["GILAS_DB_PATH"] = str(db_path)
    result = subprocess.run(
        [sys.executable, "-c", script],
        env=env,
        check=True,
        capture_output=True,
        text=True,
    )
    return result.stdout.strip()

def test_pvar_persistence_across_process_restart(tmp_path):
    db_path = tmp_path / "store.db"

    first = _run_var_script(db_path, value=1, set_value=True)
    second = _run_var_script(db_path)

    assert first == "1"
    assert second == "1"

def test_pvar_rejects_non_primitives(tmp_path, monkeypatch):
    db_path = tmp_path / "store.db"
    monkeypatch.setenv("GILAS_DB_PATH", str(db_path))

    with pytest.raises(TypeError):
        pvar("bad", initial=[1, 2, 3])

    v = pvar("ok", initial=1)
    with pytest.raises(TypeError):
        v.value = {"a": 1}

def test_persistence_across_process_restart(tmp_path):
    db_path = tmp_path / "store.db"

    first = _run_list_script(db_path, [1, 2, 3])
    second = _run_list_script(db_path, [4, 5, 6])

    assert first == "[1, 2, 3]"
    assert second == "[1, 2, 3, 4, 5, 6]"


def test_list_crud_across_process_restart(tmp_path):
    db_path = tmp_path / "store.db"

    _run_list_script(db_path, [1, 2, 3])
    script = (
        "from gilas import plist\n"
        "arr = plist('numbers')\n"
        "arr[1] = 20\n"
        "arr.append(4)\n"
        "arr.remove(1)\n"
        "arr.pop()\n"
        "print(list(arr))\n"
    )
    env = os.environ.copy()
    env["GILAS_DB_PATH"] = str(db_path)
    result = subprocess.run(
        [sys.executable, "-c", script],
        env=env,
        check=True,
        capture_output=True,
        text=True,
    )

    assert result.stdout.strip() == "[20, 3]"


def test_dict_persistence_across_process_restart(tmp_path):
    db_path = tmp_path / "store.db"

    first = _run_dict_script(db_path, {"alpha": "beta"})
    second = _run_dict_script(db_path, {"gamma": "delta"})

    assert first == "[('alpha', 'beta')]"
    assert second == "[('alpha', 'beta'), ('gamma', 'delta')]"


def test_dict_crud_across_process_restart(tmp_path):
    db_path = tmp_path / "store.db"

    _run_dict_script(db_path, {"alpha": "beta", "gamma": "delta"})
    updated = _run_dict_script(
        db_path,
        {"alpha": "omega", "epsilon": "zeta"},
        delete_keys=["gamma"],
        set_default={"theta": "lambda", "alpha": "ignored"},
    )

    assert updated == "[('alpha', 'omega'), ('epsilon', 'zeta'), ('theta', 'lambda')]"
