from __future__ import annotations

import json

from aegro.cli import app


class TestElementsGet:
    def test_get_element(self, runner, mock_settings, mock_client, temp_state):
        mock_client.get.return_value = {"_id": "elem-1", "name": "Roundup"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["elements", "get", "elem-1"])
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["name"] == "Roundup"
        mock_client.get.assert_called_once_with("/pub/v1/elements/elem-1", api_key="key-1")

    def test_get_element_not_found(self, runner, mock_settings, mock_client, temp_state):
        mock_client.get.return_value = None
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["elements", "get", "missing"])
        assert result.exit_code == 0
        assert "nao encontrad" in result.stdout.lower()

    def test_get_element_no_farm(self, runner, mock_settings, temp_state):
        result = runner.invoke(app, ["elements", "get", "elem-1"])
        assert result.exit_code != 0


class TestElementsList:
    def test_list_no_filters(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = [{"_id": "e1", "name": "Roundup"}]
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["elements", "list"])
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert len(data) == 1
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["requiredPageNumber"] == 1
        assert call_body["maximumItemsPerPageCount"] == 50

    def test_list_with_category_filter(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = []
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        runner.invoke(
            app,
            ["elements", "list", "--category", "DEFENSIVE", "--category", "FERTILIZER"],
        )
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["categories"] == ["DEFENSIVE", "FERTILIZER"]

    def test_list_with_type_filter(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = []
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        runner.invoke(
            app,
            ["elements", "list", "--type", "HERBICIDE", "--type", "INSECTICIDE"],
        )
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["types"] == ["HERBICIDE", "INSECTICIDE"]

    def test_list_with_page(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = []
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        runner.invoke(app, ["elements", "list", "--page", "3"])
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["requiredPageNumber"] == 3

    def test_list_empty_result(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = None
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["elements", "list"])
        assert result.exit_code == 0
        assert "nenhum" in result.stdout.lower()


class TestCreateDefensive:
    def test_create_defensive(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"_id": "def-1", "name": "Roundup"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(
            app,
            [
                "elements",
                "create-defensive",
                "--name",
                "Roundup",
                "--type",
                "HERBICIDE",
                "--unit",
                "L",
            ],
        )
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["name"] == "Roundup"
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["name"] == "Roundup"
        assert call_body["type"] == "HERBICIDE"
        assert call_body["measuringUnit"] == "L"
        assert "manufacturer" not in call_body

    def test_create_defensive_with_optional_fields(
        self, runner, mock_settings, mock_client, temp_state
    ):
        mock_client.post.return_value = {"_id": "def-2", "name": "Engeo"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        runner.invoke(
            app,
            [
                "elements",
                "create-defensive",
                "--name",
                "Engeo",
                "--type",
                "INSECTICIDE",
                "--unit",
                "L",
                "--manufacturer",
                "Syngenta",
                "--observations",
                "Uso em soja",
            ],
        )
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["manufacturer"] == "Syngenta"
        assert call_body["observations"] == "Uso em soja"
        assert mock_client.post.call_args.args[0] == "/pub/v1/elements/defensives"


class TestCreateFertilizer:
    def test_create_fertilizer(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"_id": "fert-1", "name": "Ureia"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(
            app,
            ["elements", "create-fertilizer", "--name", "Ureia", "--unit", "KG"],
        )
        assert result.exit_code == 0
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["name"] == "Ureia"
        assert call_body["measuringUnit"] == "KG"
        assert "type" not in call_body
        assert mock_client.post.call_args.args[0] == "/pub/v1/elements/fertilizers"


class TestCreateItem:
    def test_create_item(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"_id": "item-1", "name": "Parafuso"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(
            app,
            [
                "elements",
                "create-item",
                "--name",
                "Parafuso",
                "--type",
                "GENERAL",
                "--unit",
                "UN",
            ],
        )
        assert result.exit_code == 0
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["name"] == "Parafuso"
        assert call_body["type"] == "GENERAL"
        assert call_body["measuringUnit"] == "UN"
        assert mock_client.post.call_args.args[0] == "/pub/v1/elements/items"


class TestCreateSeed:
    def test_create_seed(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"_id": "seed-1", "name": "TMG 2381"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(
            app,
            [
                "elements",
                "create-seed",
                "--name",
                "TMG 2381",
                "--type",
                "SOYBEAN",
                "--unit",
                "KG",
            ],
        )
        assert result.exit_code == 0
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["name"] == "TMG 2381"
        assert call_body["type"] == "SOYBEAN"
        assert call_body["measuringUnit"] == "KG"
        assert mock_client.post.call_args.args[0] == "/pub/v1/elements/seeds"


class TestCreateService:
    def test_create_service(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"_id": "svc-1", "name": "Pulverizacao"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(
            app,
            [
                "elements",
                "create-service",
                "--name",
                "Pulverizacao",
                "--unit",
                "HA",
            ],
        )
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["name"] == "Pulverizacao"
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["name"] == "Pulverizacao"
        assert call_body["measuringUnit"] == "HA"
        assert "type" not in call_body
        assert "manufacturer" not in call_body
        assert mock_client.post.call_args.args[0] == "/pub/v1/elements/services"

    def test_create_service_null_result(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = None
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(
            app,
            ["elements", "create-service", "--name", "X", "--unit", "UN"],
        )
        assert result.exit_code == 0
        assert "erro" in result.stdout.lower()


class TestSetCategories:
    def test_set_both_categories(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"status": "ok"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(
            app,
            [
                "elements",
                "set-categories",
                "elem-1",
                "--revenue-category-key",
                "rev-1",
                "--expense-category-key",
                "exp-1",
            ],
        )
        assert result.exit_code == 0
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["associations"]["revenueFinancialCategory"]["key"] == "rev-1"
        assert call_body["associations"]["expenseFinancialCategory"]["key"] == "exp-1"
        assert mock_client.post.call_args.args[0] == "/pub/v1/elements/elem-1/financial-categories"

    def test_set_only_expense_category(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"status": "ok"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        runner.invoke(
            app,
            [
                "elements",
                "set-categories",
                "elem-1",
                "--expense-category-key",
                "exp-1",
            ],
        )
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert "revenueFinancialCategory" not in call_body["associations"]
        assert call_body["associations"]["expenseFinancialCategory"]["key"] == "exp-1"

    def test_set_categories_no_farm(self, runner, mock_settings, temp_state):
        result = runner.invoke(
            app,
            [
                "elements",
                "set-categories",
                "elem-1",
                "--revenue-category-key",
                "rev-1",
            ],
        )
        assert result.exit_code != 0
