from __future__ import annotations

import json

from aegro.cli import app


class TestActivitiesGet:
    def test_get_activity(self, runner, mock_settings, mock_client, temp_state):
        mock_client.get.return_value = {"_id": "act-1", "type": "SOWING"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["activities", "get", "act-1"])
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["type"] == "SOWING"
        mock_client.get.assert_called_once_with("/pub/v1/activities/act-1", api_key="key-1")

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

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


class TestActivitiesList:
    def test_list_no_filters(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = [{"_id": "a1", "type": "SOWING"}]
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["activities", "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_crop_key(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = []
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        runner.invoke(app, ["activities", "list", "--crop-key", "crop-1"])
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["cropKeys"] == ["crop-1"]

    def test_list_with_status_and_type(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = []
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        runner.invoke(
            app,
            [
                "activities",
                "list",
                "--status",
                "PLANNED",
                "--status",
                "COMPLETED",
                "--type",
                "SOWING",
            ],
        )
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["statuses"] == ["PLANNED", "COMPLETED"]
        assert call_body["types"] == ["SOWING"]

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


class TestActivitiesPlan:
    def test_get_activity_plan(self, runner, mock_settings, mock_client, temp_state):
        mock_client.get.return_value = {"_id": "plan-1", "activityKey": "act-1"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["activities", "plan", "act-1"])
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["activityKey"] == "act-1"
        mock_client.get.assert_called_once_with("/pub/v1/activities/act-1/plan", api_key="key-1")

    def test_get_activity_plan_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, ["activities", "plan", "missing"])
        assert result.exit_code == 0
        assert "nao encontrad" in result.stdout.lower()


class TestActivitiesRealizations:
    def test_realizations_no_filters(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = [{"_id": "r1"}]
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["activities", "realizations"])
        assert result.exit_code == 0
        assert mock_client.post.call_args.args[0] == "/pub/v1/activities/realizations/filter"
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["requiredPageNumber"] == 1

    def test_realizations_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,
            [
                "activities",
                "realizations",
                "--activity-key",
                "act-1",
                "--crop-key",
                "crop-1",
                "--start-date",
                "2025-01-01",
                "--end-date",
                "2025-12-31",
            ],
        )
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["activityKeys"] == ["act-1"]
        assert call_body["cropKeys"] == ["crop-1"]
        assert call_body["startDate"] == "2025-01-01"
        assert call_body["endDate"] == "2025-12-31"

    def test_realizations_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, ["activities", "realizations"])
        assert result.exit_code == 0
        assert "nenhum" in result.stdout.lower()


class TestActivitiesGetPlan:
    def test_get_plan(self, runner, mock_settings, mock_client, temp_state):
        mock_client.get.return_value = {"_id": "plan-1", "type": "SOWING"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["activities", "get-plan", "plan-1"])
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["_id"] == "plan-1"
        mock_client.get.assert_called_once_with("/pub/v1/activities/plans/plan-1", api_key="key-1")

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


class TestActivitiesGetRealization:
    def test_get_realization(self, runner, mock_settings, mock_client, temp_state):
        mock_client.get.return_value = {"_id": "real-1", "status": "COMPLETED"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["activities", "get-realization", "real-1"])
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["status"] == "COMPLETED"
        mock_client.get.assert_called_once_with(
            "/pub/v1/activities/realizations/real-1", api_key="key-1"
        )

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


class TestActivitiesCreatePlan:
    def test_create_plan_required_fields(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"_id": "new-plan", "type": "SOWING"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(
            app,
            [
                "activities",
                "create-plan",
                "--crop-key",
                "crop-1",
                "--type",
                "SOWING",
                "--start-date",
                "2025-06-01",
            ],
        )
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["_id"] == "new-plan"
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["cropKey"] == "crop-1"
        assert call_body["type"] == "SOWING"
        assert call_body["startDate"] == "2025-06-01"
        assert mock_client.post.call_args.args[0] == "/pub/v1/activities/plan"

    def test_create_plan_all_fields(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"_id": "new-plan"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        inputs_json = json.dumps([{"productKey": "p1", "quantity": 10}])
        runner.invoke(
            app,
            [
                "activities",
                "create-plan",
                "--crop-key",
                "crop-1",
                "--type",
                "APPLICATION",
                "--start-date",
                "2025-06-01",
                "--activity-key",
                "act-1",
                "--crop-glebe-key",
                "g1",
                "--crop-glebe-key",
                "g2",
                "--end-date",
                "2025-06-15",
                "--observations",
                "Aplicacao de defensivo",
                "--inputs",
                inputs_json,
            ],
        )
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["cropKey"] == "crop-1"
        assert call_body["type"] == "APPLICATION"
        assert call_body["startDate"] == "2025-06-01"
        assert call_body["activityKey"] == "act-1"
        assert call_body["cropGlebeKeys"] == ["g1", "g2"]
        assert call_body["endDate"] == "2025-06-15"
        assert call_body["observations"] == "Aplicacao de defensivo"
        assert call_body["inputs"] == [{"productKey": "p1", "quantity": 10}]

    def test_create_plan_failure(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,
            [
                "activities",
                "create-plan",
                "--crop-key",
                "crop-1",
                "--type",
                "SOWING",
                "--start-date",
                "2025-06-01",
            ],
        )
        assert result.exit_code == 0
        assert "falha" in result.stdout.lower()

    def test_create_plan_no_farm(self, runner, mock_settings, temp_state):
        result = runner.invoke(
            app,
            [
                "activities",
                "create-plan",
                "--crop-key",
                "crop-1",
                "--type",
                "SOWING",
                "--start-date",
                "2025-06-01",
            ],
        )
        assert result.exit_code != 0
