"""Tests for cli.py using Click's test runner."""

from __future__ import annotations

from unittest.mock import MagicMock, patch

import pytest
import responses as responses_lib
from click.testing import CliRunner

from modpack_checker.cli import cli
from modpack_checker.curseforge import CurseForgeNotFoundError


@pytest.fixture
def runner():
    return CliRunner()


@pytest.fixture
def mock_cfg(tmp_path):
    """Return a Config-like mock backed by a real temp database."""
    cfg = MagicMock()
    cfg.curseforge_api_key = "test-api-key"
    cfg.database_path = str(tmp_path / "test.db")
    cfg.discord_webhook_url = None
    cfg.notification_on_update = True
    cfg.check_interval_hours = 6
    return cfg


# ---------------------------------------------------------------------------
# Root / help
# ---------------------------------------------------------------------------


def test_help(runner):
    result = runner.invoke(cli, ["--help"])
    assert result.exit_code == 0
    assert "Modpack Version Checker" in result.output


def test_version(runner):
    result = runner.invoke(cli, ["--version"])
    assert result.exit_code == 0
    assert "1.0.0" in result.output


# ---------------------------------------------------------------------------
# config show
# ---------------------------------------------------------------------------


def test_config_show(runner, mock_cfg):
    mock_cfg.curseforge_api_key = "abcd1234efgh5678"
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["config", "show"])
    assert result.exit_code == 0
    assert "abcd" in result.output   # first 4 chars
    assert "5678" in result.output   # last 4 chars


def test_config_show_no_key(runner, mock_cfg):
    mock_cfg.curseforge_api_key = ""
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["config", "show"])
    assert result.exit_code == 0
    assert "Not configured" in result.output


# ---------------------------------------------------------------------------
# list
# ---------------------------------------------------------------------------


def test_list_empty(runner, mock_cfg):
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["list"])
    assert result.exit_code == 0
    assert "empty" in result.output.lower()


def test_list_with_modpacks(runner, mock_cfg, tmp_path):
    from modpack_checker.database import Database
    db = Database(str(tmp_path / "test.db"))
    db.add_modpack(111, "Pack Alpha")
    db.add_modpack(222, "Pack Beta")

    mock_cfg.database_path = str(tmp_path / "test.db")
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["list"])

    assert result.exit_code == 0
    assert "Pack Alpha" in result.output
    assert "Pack Beta" in result.output


# ---------------------------------------------------------------------------
# add
# ---------------------------------------------------------------------------


def test_add_requires_api_key(runner, mock_cfg):
    mock_cfg.curseforge_api_key = ""
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["add", "12345"])
    assert result.exit_code == 1
    assert "API key" in result.output


@responses_lib.activate
def test_add_success(runner, mock_cfg):
    responses_lib.add(
        responses_lib.GET,
        "https://api.curseforge.com/v1/mods/12345",
        json={"data": {"id": 12345, "name": "Test Modpack", "latestFiles": []}},
        status=200,
    )
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["add", "12345"])
    assert result.exit_code == 0
    assert "Test Modpack" in result.output
    assert "tracking" in result.output.lower()


@responses_lib.activate
def test_add_not_found(runner, mock_cfg):
    responses_lib.add(
        responses_lib.GET,
        "https://api.curseforge.com/v1/mods/99999",
        status=404,
    )
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["add", "99999"])
    assert result.exit_code == 1
    assert "99999" in result.output


@responses_lib.activate
def test_add_duplicate_shows_warning(runner, mock_cfg, tmp_path):
    responses_lib.add(
        responses_lib.GET,
        "https://api.curseforge.com/v1/mods/12345",
        json={"data": {"id": 12345, "name": "Test Modpack", "latestFiles": []}},
        status=200,
    )
    from modpack_checker.database import Database
    db = Database(str(tmp_path / "test.db"))
    db.add_modpack(12345, "Test Modpack")

    mock_cfg.database_path = str(tmp_path / "test.db")
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["add", "12345"])
    assert "already tracked" in result.output.lower()


# ---------------------------------------------------------------------------
# remove
# ---------------------------------------------------------------------------


def test_remove_not_in_list(runner, mock_cfg):
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["remove", "99999"], input="y\n")
    assert result.exit_code == 1
    assert "not in your watch list" in result.output


def test_remove_success(runner, mock_cfg, tmp_path):
    from modpack_checker.database import Database
    db = Database(str(tmp_path / "test.db"))
    db.add_modpack(12345, "Test Pack")

    mock_cfg.database_path = str(tmp_path / "test.db")
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["remove", "12345"], input="y\n")
    assert result.exit_code == 0
    assert "Removed" in result.output


def test_remove_aborted(runner, mock_cfg, tmp_path):
    from modpack_checker.database import Database
    db = Database(str(tmp_path / "test.db"))
    db.add_modpack(12345, "Test Pack")

    mock_cfg.database_path = str(tmp_path / "test.db")
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["remove", "12345"], input="n\n")
    # Aborted — pack should still exist
    assert db.get_modpack(12345) is not None


# ---------------------------------------------------------------------------
# check
# ---------------------------------------------------------------------------


def test_check_empty_list(runner, mock_cfg):
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["check"])
    assert result.exit_code == 0
    assert "No modpacks" in result.output


@responses_lib.activate
def test_check_up_to_date(runner, mock_cfg, tmp_path):
    from modpack_checker.database import Database
    db = Database(str(tmp_path / "test.db"))
    db.add_modpack(12345, "Test Pack")
    db.update_version(12345, "1.0.0")

    responses_lib.add(
        responses_lib.GET,
        "https://api.curseforge.com/v1/mods/12345",
        json={
            "data": {
                "id": 12345,
                "name": "Test Pack",
                "latestFiles": [
                    {
                        "id": 1,
                        "displayName": "1.0.0",
                        "fileName": "pack-1.0.0.zip",
                        "fileDate": "2026-01-01T00:00:00Z",
                    }
                ],
            }
        },
        status=200,
    )

    mock_cfg.database_path = str(tmp_path / "test.db")
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["check", "--no-notify"])

    assert result.exit_code == 0
    assert "up to date" in result.output.lower()


@responses_lib.activate
def test_check_update_available(runner, mock_cfg, tmp_path):
    from modpack_checker.database import Database
    db = Database(str(tmp_path / "test.db"))
    db.add_modpack(12345, "Test Pack")
    db.update_version(12345, "1.0.0")

    responses_lib.add(
        responses_lib.GET,
        "https://api.curseforge.com/v1/mods/12345",
        json={
            "data": {
                "id": 12345,
                "name": "Test Pack",
                "latestFiles": [
                    {
                        "id": 2,
                        "displayName": "1.1.0",
                        "fileName": "pack-1.1.0.zip",
                        "fileDate": "2026-02-01T00:00:00Z",
                    }
                ],
            }
        },
        status=200,
    )

    mock_cfg.database_path = str(tmp_path / "test.db")
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["check", "--no-notify"])

    assert result.exit_code == 0
    assert "1.1.0" in result.output


# ---------------------------------------------------------------------------
# status
# ---------------------------------------------------------------------------


def test_status_not_found(runner, mock_cfg):
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["status", "99999"])
    assert result.exit_code == 1
    assert "not in your watch list" in result.output


def test_status_shows_info(runner, mock_cfg, tmp_path):
    from modpack_checker.database import Database
    db = Database(str(tmp_path / "test.db"))
    db.add_modpack(12345, "Test Pack")
    db.update_version(12345, "2.0.0")

    mock_cfg.database_path = str(tmp_path / "test.db")
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["status", "12345"])

    assert result.exit_code == 0
    assert "Test Pack" in result.output
    assert "2.0.0" in result.output


# ---------------------------------------------------------------------------
# notifications command
# ---------------------------------------------------------------------------


def test_notifications_disable(runner, mock_cfg, tmp_path):
    from modpack_checker.database import Database
    db = Database(str(tmp_path / "test.db"))
    db.add_modpack(12345, "Test Pack")

    mock_cfg.database_path = str(tmp_path / "test.db")
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["notifications", "12345", "--disable"])

    assert result.exit_code == 0
    assert "disabled" in result.output
    assert db.get_modpack(12345).notification_enabled is False


def test_notifications_enable(runner, mock_cfg, tmp_path):
    from modpack_checker.database import Database
    db = Database(str(tmp_path / "test.db"))
    db.add_modpack(12345, "Test Pack")
    db.toggle_notifications(12345, False)

    mock_cfg.database_path = str(tmp_path / "test.db")
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["notifications", "12345", "--enable"])

    assert result.exit_code == 0
    assert "enabled" in result.output
    assert db.get_modpack(12345).notification_enabled is True


def test_notifications_missing_modpack(runner, mock_cfg):
    with patch("modpack_checker.cli.Config.load", return_value=mock_cfg):
        result = runner.invoke(cli, ["notifications", "99999", "--enable"])
    assert result.exit_code == 1
