from dataclasses import dataclass

from typer.testing import CliRunner

from awspipe.backend import QueryResult
from awspipe.cli import app
from awspipe.engine import InspectRow
from awspipe.providers.base import Column, TableProvider


runner = CliRunner()


@dataclass
class FakeDoctorStatus:
    profile: str | None
    region: str
    account_id: str
    arn: str
    cache_path: str


class FakeBackend:
    def __init__(self) -> None:
        self.cleared = False

    def clear_cache(self) -> None:
        self.cleared = True


class FakeEngine:
    def __init__(self) -> None:
        self.backend = FakeBackend()
        self.provider = TableProvider(
            name="aws_account",
            description="account table",
            columns=(Column("account_id", "VARCHAR", "Account id."),),
            scope="global",
            fetcher=lambda context: [],
        )

    def available_tables(self):
        return [self.provider]

    def inspect_table(self, table_name):
        return self.provider, [InspectRow(column="account_id", type_name="VARCHAR", description="Account id.")]

    def doctor(self, profile=None, region=None):
        return FakeDoctorStatus(profile=profile, region=region or "eu-west-1", account_id="123456789012", arn="arn:aws:iam::123456789012:user/test", cache_path="C:/tmp/awspipe.duckdb")

    def query(self, sql, profile=None, region=None, refresh=False, all_regions=False):
        return QueryResult(columns=["account_id"], rows=[("123456789012",)])


def test_tables_command(monkeypatch) -> None:
    fake_engine = FakeEngine()
    monkeypatch.setattr("awspipe.cli.build_engine", lambda: fake_engine)

    result = runner.invoke(app, ["tables"])

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


def test_inspect_command(monkeypatch) -> None:
    fake_engine = FakeEngine()
    monkeypatch.setattr("awspipe.cli.build_engine", lambda: fake_engine)

    result = runner.invoke(app, ["inspect", "aws_account"])

    assert result.exit_code == 0
    assert "account_id (VARCHAR)" in result.output


def test_query_command_csv_output(monkeypatch) -> None:
    fake_engine = FakeEngine()
    monkeypatch.setattr("awspipe.cli.build_engine", lambda: fake_engine)

    result = runner.invoke(app, ["query", "select * from aws_account", "--output", "csv"])

    assert result.exit_code == 0
    assert "account_id" in result.output
    assert "123456789012" in result.output


def test_query_command_all_regions(monkeypatch) -> None:
    calls = {}

    class RecordingEngine(FakeEngine):
        def query(self, sql, profile=None, region=None, refresh=False, all_regions=False):
            calls["all_regions"] = all_regions
            return super().query(sql, profile=profile, region=region, refresh=refresh, all_regions=all_regions)

    fake_engine = RecordingEngine()
    monkeypatch.setattr("awspipe.cli.build_engine", lambda: fake_engine)

    result = runner.invoke(app, ["query", "select * from aws_account", "--all"])

    assert result.exit_code == 0
    assert calls["all_regions"] is True


def test_doctor_command(monkeypatch) -> None:
    fake_engine = FakeEngine()
    monkeypatch.setattr("awspipe.cli.build_engine", lambda: fake_engine)

    result = runner.invoke(app, ["doctor", "--profile", "dev", "--region", "eu-west-1"])

    assert result.exit_code == 0
    assert "profile: dev" in result.output
    assert "region: eu-west-1" in result.output


def test_cache_clear_command(monkeypatch) -> None:
    fake_engine = FakeEngine()
    monkeypatch.setattr("awspipe.cli.build_engine", lambda: fake_engine)

    result = runner.invoke(app, ["cache", "clear"])

    assert result.exit_code == 0
    assert fake_engine.backend.cleared is True
