"""Tests for the l4d2web Flask CLI subcommands."""
from __future__ import annotations
from click.testing import CliRunner
import pytest
from sqlalchemy import select

from l4d2web.app import create_app
from l4d2web.cli import workshop_refresh
from l4d2web.db import init_db, session_scope
from l4d2web.models import Job


@pytest.fixture
def app_env(tmp_path, monkeypatch):
    db_url = f"sqlite:///{tmp_path/'cli.db'}"
    monkeypatch.setenv("DATABASE_URL", db_url)
    monkeypatch.setenv("LEFT4ME_ROOT", str(tmp_path))
    app = create_app({"TESTING": True, "DATABASE_URL": db_url, "SECRET_KEY": "test"})
    init_db()
    return app


def test_workshop_refresh_enqueues_job(app_env):
    runner = CliRunner()
    with app_env.app_context():
        result = runner.invoke(workshop_refresh, [])
        assert result.exit_code == 0, result.output
        assert "enqueued refresh_workshop_items job" in result.output
        with session_scope() as db:
            jobs = db.scalars(select(Job).where(Job.operation == "refresh_workshop_items")).all()
            assert len(jobs) == 1
            assert jobs[0].state == "queued"
            assert jobs[0].user_id is None
            assert jobs[0].server_id is None


def test_workshop_refresh_is_idempotent_when_job_queued(app_env):
    runner = CliRunner()
    with app_env.app_context():
        first = runner.invoke(workshop_refresh, [])
        second = runner.invoke(workshop_refresh, [])
        assert first.exit_code == 0
        assert second.exit_code == 0
        assert "already queued" in second.output
        with session_scope() as db:
            jobs = db.scalars(select(Job).where(Job.operation == "refresh_workshop_items")).all()
            assert len(jobs) == 1, "must not insert a second job when one is already queued"


@pytest.mark.parametrize("active_state", ["running", "cancelling"])
def test_workshop_refresh_is_idempotent_when_job_active(app_env, active_state):
    runner = CliRunner()
    with app_env.app_context():
        with session_scope() as db:
            db.add(Job(
                user_id=None, server_id=None,
                operation="refresh_workshop_items", state=active_state,
            ))
        result = runner.invoke(workshop_refresh, [])
        assert result.exit_code == 0
        assert f"already {active_state}" in result.output
        with session_scope() as db:
            jobs = db.scalars(select(Job).where(Job.operation == "refresh_workshop_items")).all()
            assert len(jobs) == 1
