from __future__ import annotations

import json

from aegro.cli import app


class TestBankAccountsGet:
    def test_get_bank_account(self, runner, mock_settings, mock_client, temp_state):
        mock_client.get.return_value = {"_id": "ba1", "name": "Conta Itau"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["bank-accounts", "get", "ba1"])
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["name"] == "Conta Itau"
        mock_client.get.assert_called_once_with("/pub/v1/bank-accounts/ba1", api_key="key-1")

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

    def test_get_bank_account_no_farm(self, runner, mock_settings, temp_state):
        result = runner.invoke(app, ["bank-accounts", "get", "ba1"])
        assert result.exit_code != 0


class TestBankAccountsList:
    def test_list_no_filters(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = [{"_id": "ba1", "name": "Conta Itau"}]
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(app, ["bank-accounts", "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"])
        result = runner.invoke(
            app,
            [
                "bank-accounts",
                "list",
                "--search-text",
                "Itau",
                "--bank-name",
                "Itau Unibanco",
            ],
        )
        assert result.exit_code == 0
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["searchText"] == "Itau"
        assert call_body["bankName"] == "Itau Unibanco"

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


class TestBankAccountsCreate:
    def test_create_bank_account(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = {"_id": "ba-new", "name": "Conta BB"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(
            app,
            [
                "bank-accounts",
                "create",
                "--name",
                "Conta BB",
                "--balance",
                "10000",
                "--balance-currency",
                "BRL",
            ],
        )
        assert result.exit_code == 0
        data = json.loads(result.stdout)
        assert data["_id"] == "ba-new"
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["name"] == "Conta BB"
        assert call_body["balance"] == {"currencyCode": "BRL", "amount": 10000.0}
        assert "initialBalance" not in call_body  # not passed in this test

    def test_create_bank_account_is_default(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,
            [
                "bank-accounts",
                "create",
                "--name",
                "Conta Principal",
                "--is-default",
            ],
        )
        assert result.exit_code == 0
        assert "criada" in result.stdout.lower()
        url = mock_client.post.call_args.args[0]
        assert "isDefault=true" in url

    def test_create_bank_account_not_default(self, runner, mock_settings, mock_client, temp_state):
        mock_client.post.return_value = None
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        runner.invoke(
            app,
            ["bank-accounts", "create", "--name", "Conta Secundaria"],
        )
        url = mock_client.post.call_args.args[0]
        assert "isDefault=false" in url

    def test_create_bank_account_with_bank_details(
        self, runner, mock_settings, mock_client, temp_state
    ):
        mock_client.post.return_value = {"_id": "ba-new"}
        runner.invoke(app, ["farms", "select", "Fazenda Sul"])
        result = runner.invoke(
            app,
            [
                "bank-accounts",
                "create",
                "--name",
                "Conta Completa",
                "--bank-name",
                "Banco do Brasil",
                "--bank-code",
                "001",
                "--branch-code",
                "1234",
                "--code",
                "56789",
                "--initial-balance",
                "5000",
                "--initial-balance-currency",
                "BRL",
                "--initial-balance-date",
                "2025-01-01",
            ],
        )
        assert result.exit_code == 0
        call_body = mock_client.post.call_args.kwargs["json_body"]
        assert call_body["bankName"] == "Banco do Brasil"
        assert call_body["bankCode"] == "001"
        assert call_body["branchCode"] == "1234"
        assert call_body["code"] == "56789"
        assert call_body["initialBalance"] == {"currencyCode": "BRL", "amount": 5000.0}
        assert call_body["initialBalanceDate"] == "2025-01-01"

    def test_create_bank_account_no_farm(self, runner, mock_settings, temp_state):
        result = runner.invoke(
            app,
            ["bank-accounts", "create", "--name", "Conta"],
        )
        assert result.exit_code != 0
