from __future__ import annotations

import json

from aegro.cli import app


class TestFinancialCategoriesGet:
    def test_get_category(self, runner, mock_settings, mock_client, temp_state):
        mock_client.get.return_value = {"_id": "fc-1", "description": "Insumos"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["fin-categories", "get", "fc-1"])
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["description"] == "Insumos"
        mock_client.get.assert_called_once_with(
            "/pub/v1/financial-categories/fc-1", api_key="key-1"
        )

    def test_get_category_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, ["fin-categories", "get", "missing"])
        assert result.exit_code == 0
        assert "nao encontrad" in result.stdout.lower()

    def test_get_category_no_farm(self, runner, mock_settings, temp_state):
        result = runner.invoke(app, ["fin-categories", "get", "fc-1"])
        assert result.exit_code != 0


class TestFinancialCategoriesList:
    def test_list_no_filters(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = [{"_id": "fc-1", "description": "Insumos"}]
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["fin-categories", "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_filters(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = []
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        runner.invoke(
            app,
            [
                "fin-categories",
                "list",
                "--type",
                "EXPENSE",
                "--type",
                "REVENUE",
                "--operation-type",
                "DEBIT",
                "--status",
                "ACTIVE",
                "--search-text",
                "Insumos",
            ],
        )
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["types"] == ["EXPENSE", "REVENUE"]
        assert call_body["operationTypes"] == ["DEBIT"]
        assert call_body["statuses"] == ["ACTIVE"]
        assert call_body["searchText"] == "Insumos"

    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, ["fin-categories", "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, ["fin-categories", "list"])
        assert result.exit_code == 0
        assert "nenhum" in result.stdout.lower()


class TestFinancialCategoriesCreate:
    def test_create_required_fields(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"_id": "fc-new"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(
            app,
            [
                "fin-categories",
                "create",
                "--description",
                "Insumos",
                "--type",
                "EXPENSE",
                "--operation-type",
                "DEBIT",
                "--status",
                "ACTIVE",
                "--bill-type",
                "PAYABLE",
                "--code",
                "1.1",
            ],
        )
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["_id"] == "fc-new"
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["description"] == "Insumos"
        assert call_body["type"] == "EXPENSE"
        assert call_body["operationType"] == "DEBIT"
        assert call_body["status"] == "ACTIVE"
        assert call_body["billType"] == "PAYABLE"
        assert call_body["code"] == "1.1"
        assert "observations" not in call_body
        assert "parentCode" not in call_body
        assert mock_client.post.call_args.args[0] == "/pub/v1/financial-categories"

    def test_create_all_fields(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"_id": "fc-new"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        runner.invoke(
            app,
            [
                "fin-categories",
                "create",
                "--description",
                "Sementes",
                "--type",
                "EXPENSE",
                "--operation-type",
                "DEBIT",
                "--status",
                "ACTIVE",
                "--bill-type",
                "PAYABLE",
                "--code",
                "1.1.1",
                "--observations",
                "Subcategoria de insumos",
                "--parent-code",
                "1.1",
            ],
        )
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["description"] == "Sementes"
        assert call_body["code"] == "1.1.1"
        assert call_body["observations"] == "Subcategoria de insumos"
        assert call_body["parentCode"] == "1.1"

    def test_create_no_farm(self, runner, mock_settings, temp_state):
        result = runner.invoke(
            app,
            [
                "fin-categories",
                "create",
                "--description",
                "Insumos",
                "--type",
                "EXPENSE",
                "--operation-type",
                "DEBIT",
                "--status",
                "ACTIVE",
                "--bill-type",
                "PAYABLE",
                "--code",
                "1.1",
            ],
        )
        assert result.exit_code != 0


class TestFinancialCategoriesSubcategories:
    def test_subcategories_no_filters(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = [{"_id": "sub-1"}]
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["fin-categories", "subcategories", "fc-1"])
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert len(data) == 1
        assert mock_client.post.call_args.args[0] == "/pub/v1/financial-categories/fc-1/filter"
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["requiredPageNumber"] == 1
        assert call_body["maximumItemsPerPageCount"] == 50

    def test_subcategories_with_filters(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = []
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        runner.invoke(
            app,
            [
                "fin-categories",
                "subcategories",
                "fc-1",
                "--element-category",
                "CAT1",
                "--element-category",
                "CAT2",
                "--page",
                "2",
            ],
        )
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["elementCategories"] == ["CAT1", "CAT2"]
        assert call_body["requiredPageNumber"] == 2

    def test_subcategories_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, ["fin-categories", "subcategories", "fc-1"])
        assert result.exit_code == 0
        assert "nenhum" in result.stdout.lower()
