"""Test CLI functions to get flow cells in the Status database."""

from datetime import datetime

from click.testing import CliRunner

from cg.cli.get import get
from cg.constants import EXIT_FAIL, EXIT_SUCCESS
from cg.models.cg_config import CGConfig
from cg.store.models import Flowcell, Sample
from cg.store.store import Store
from tests.store_helpers import StoreHelpers


def test_get_flow_cell_bad_flow_cell(cli_runner: CliRunner, base_context: CGConfig):
    """Test that trying to get a flow cell using a non-existing flow cell fails."""
    # GIVEN an empty database

    # WHEN getting a flow cell
    result = cli_runner.invoke(get, ["flow-cell", "does_not_exist"], obj=base_context)

    # THEN it should complain about missing flow cell instead of getting a flow cell
    assert result.exit_code == EXIT_FAIL


def test_get_flow_cell_required(
    cli_runner: CliRunner, base_context: CGConfig, disk_store: Store, helpers: StoreHelpers
):
    """Test to get a flow cell using only the required arguments."""
    # GIVEN a database with a flow cell
    flow_cell: Flowcell = helpers.add_flow_cell(store=disk_store)

    # WHEN getting a flow cell
    result = cli_runner.invoke(get, ["flow-cell", flow_cell.name], obj=base_context)

    # THEN exist successfully
    assert result.exit_code == EXIT_SUCCESS


def test_get_flow_cell_output(
    cli_runner: CliRunner, base_context: CGConfig, disk_store: Store, helpers: StoreHelpers
):
    """Test that the output has the data of the flow cell."""
    # GIVEN a database with a flow cell with data
    flow_cell: Flowcell = helpers.add_flow_cell(disk_store)

    # WHEN getting a flow cell
    result = cli_runner.invoke(get, ["flow-cell", flow_cell.name], obj=base_context)

    # THEN exist successfully
    assert result.exit_code == EXIT_SUCCESS

    # THEN it should have been returned
    assert flow_cell.name in result.output
    assert flow_cell.sequencer_type in result.output
    assert flow_cell.sequencer_name in result.output
    assert str(flow_cell.sequenced_at.date()) in result.output
    assert flow_cell.status in result.output


def test_get_flow_cell_archived_at_none(
    cli_runner: CliRunner, base_context: CGConfig, disk_store: Store, helpers: StoreHelpers
):
    """Test that the output when archived at is none."""
    # GIVEN a database with a flow cell with data
    flow_cell: Flowcell = helpers.add_flow_cell(store=disk_store, archived_at=None)

    # WHEN getting a flow cell
    result = cli_runner.invoke(get, ["flow-cell", flow_cell.name], obj=base_context)

    # THEN exist successfully
    assert result.exit_code == EXIT_SUCCESS

    # THEN log that the flow cell is on disk
    assert "ondisk" in result.output


def test_get_flow_cell_archived_at_date(
    cli_runner: CliRunner,
    base_context: CGConfig,
    disk_store: Store,
    helpers: StoreHelpers,
    timestamp: datetime,
):
    """Test that the output has the data of the flow cell."""
    # GIVEN a database with a flowcell with data
    flow_cell: Flowcell = helpers.add_flow_cell(store=disk_store, archived_at=timestamp)

    # WHEN getting a flow cell
    result = cli_runner.invoke(get, ["flow-cell", flow_cell.name], obj=base_context)

    # THEN exist successfully
    assert result.exit_code == EXIT_SUCCESS

    # THEN it should have been returned
    assert str(timestamp.date()) in result.output


def test_get_flow_cell_samples_without_samples(
    cli_runner: CliRunner, base_context: CGConfig, disk_store: Store, helpers: StoreHelpers, caplog
):
    """Test that the output without samples."""
    # GIVEN a database with a flow cell without related samples
    flow_cell: Flowcell = helpers.add_flow_cell(disk_store)

    # WHEN getting a flow cell with the --samples flag
    result = cli_runner.invoke(get, ["flow-cell", flow_cell.name, "--samples"], obj=base_context)

    # THEN exist successfully
    assert result.exit_code == EXIT_SUCCESS

    # THEN a message about no samples should have been displayed
    assert "No samples found on flow cell" in caplog.text


def test_get_flow_cell_samples(
    cli_runner: CliRunner, base_context: CGConfig, disk_store: Store, helpers: StoreHelpers
):
    """Test that the output has the samples of the flow cell."""
    # GIVEN a database with a flow cell with related samples
    samples: list[Sample] = helpers.add_samples(store=disk_store)
    flow_cell: Flowcell = helpers.add_flow_cell(store=disk_store, samples=samples)

    # WHEN getting a flow cell with the --samples flag
    result = cli_runner.invoke(get, ["flow-cell", flow_cell.name, "--samples"], obj=base_context)

    # THEN exist successfully
    assert result.exit_code == EXIT_SUCCESS

    # THEN all related samples should be listed in the output
    for sample in flow_cell.samples:
        assert sample.internal_id in result.output


def test_get_flow_cell_no_samples_without_samples(
    cli_runner: CliRunner, base_context: CGConfig, disk_store: Store, helpers: StoreHelpers
):
    """Test that the output shows no samples of the flow cell."""
    # GIVEN a database with a flow cell without related samples
    flow_cell: Flowcell = helpers.add_flow_cell(disk_store)

    # WHEN getting a flow cell with the --no-samples flag
    result = cli_runner.invoke(get, ["flow-cell", flow_cell.name, "--no-samples"], obj=base_context)

    # THEN exist successfully
    assert result.exit_code == EXIT_SUCCESS


def test_get_flow_cell_no_samples_with_samples(
    cli_runner: CliRunner, base_context: CGConfig, disk_store: Store, helpers: StoreHelpers
):
    """Test that the output has the data of the flow cell."""
    # GIVEN a database with a flow cell with related samples
    samples: Sample = helpers.add_samples(store=disk_store)
    flow_cell: Flowcell = helpers.add_flow_cell(store=disk_store, samples=samples)

    # WHEN getting a flow cell with the --no-samples flag
    result = cli_runner.invoke(get, ["flow-cell", flow_cell.name, "--no-samples"], obj=base_context)

    # THEN exist successfully
    assert result.exit_code == EXIT_SUCCESS

    # THEN no related samples should be listed in the output
    for sample in flow_cell.samples:
        assert sample.internal_id not in result.output
