import os
from unittest.mock import MagicMock

import pytest
from rich.console import Console

from cli_framework.app import create_app
from cli_framework.color import (
    LazyConsole,
    _force_color_callback,
    _no_color_callback,
    _reset_console,
    get_console,
)
from cli_framework.context import AppContext, get_context
from cli_framework.logging import setup_logging


@pytest.fixture(autouse=True)
def reset_console(monkeypatch):
    """Reset the console singleton and env vars before and after each test."""
    _reset_console()
    monkeypatch.delenv("NO_COLOR", raising=False)
    monkeypatch.delenv("FORCE_COLOR", raising=False)
    yield
    _reset_console()
    monkeypatch.delenv("NO_COLOR", raising=False)
    monkeypatch.delenv("FORCE_COLOR", raising=False)


def test_get_console_returns_singleton():
    c1 = get_console()
    c2 = get_console()
    assert c1 is c2


def test_reset_console_resets_singleton():
    c1 = get_console()
    _reset_console()
    c2 = get_console()
    assert c1 is not c2


def test_no_color_env_var(monkeypatch):
    monkeypatch.setenv("NO_COLOR", "1")
    monkeypatch.delenv("FORCE_COLOR", raising=False)
    c = get_console()
    assert c.no_color is True


def test_force_color_env_var(monkeypatch):
    monkeypatch.delenv("NO_COLOR", raising=False)
    monkeypatch.setenv("FORCE_COLOR", "1")
    c = get_console()
    assert c._force_terminal is True


def test_lazy_console_proxies_attributes():
    lazy = LazyConsole()
    # size is a real Console method; should proxy to the real console
    assert hasattr(lazy, "size")
    # print should be accessible
    assert callable(lazy.print)


def test_no_color_callback_sets_env_and_resets(monkeypatch):
    monkeypatch.delenv("NO_COLOR", raising=False)
    # warm up the singleton so we can verify reset
    c1 = get_console()
    _no_color_callback(True)
    assert os.environ.get("NO_COLOR") == "1"
    c2 = get_console()
    assert c1 is not c2
    assert c2.no_color is True


def test_force_color_callback_sets_env_and_resets(monkeypatch):
    monkeypatch.delenv("FORCE_COLOR", raising=False)
    c1 = get_console()
    _force_color_callback(True)
    assert os.environ.get("FORCE_COLOR") == "1"
    c2 = get_console()
    assert c1 is not c2
    assert c2._force_terminal is True


def test_create_app_returns_typer_with_settings():
    import typer

    app = create_app("myapp", "My help")
    assert isinstance(app, typer.Typer)
    assert app.info.name == "myapp"
    assert app.info.help == "My help"
    assert app.info.no_args_is_help is True
    assert app.rich_markup_mode == "rich"
    assert app.pretty_exceptions_enable is False


def test_app_context_dataclass_fields_and_defaults():
    console = Console()
    ctx = AppContext(console=console)
    assert ctx.console is console
    assert ctx.verbose is False
    ctx2 = AppContext(console=console, verbose=True)
    assert ctx2.verbose is True


def test_get_context_returns_app_context():
    fake_ctx = MagicMock()
    expected = AppContext(console=Console(), verbose=True)
    fake_ctx.obj = expected
    result = get_context(fake_ctx)
    assert result is expected


def test_setup_logging_configures_without_error():
    # should not raise
    setup_logging(verbose=False)
    setup_logging(verbose=True)
