from __future__ import annotations

from typing import Optional

import typer

from aegro.cli._config import get_client, require_farm
from aegro.cli._errors import handle_error
from aegro.cli._output import OutputFormat, format_output
from aegro.validation import validate_key

financial_app = typer.Typer(help="Lancamentos financeiros e parcelas.")


@financial_app.command("bill")
def get_bill(
    bill_key: str = typer.Argument(help="Chave unica do lancamento financeiro."),
    output: OutputFormat = typer.Option(
        OutputFormat.json, "--output", "-o", help="Formato: json|table|csv"
    ),
) -> None:
    """Retorna os dados de um lancamento financeiro (conta) pelo seu identificador.

    EXAMPLES:
      aegro financial bill abc123
      aegro financial bill abc123 --output table
    """
    try:
        _, api_key = require_farm()
        client = get_client()
        result = client.get(f"/pub/v1/bills/{validate_key(bill_key)}", api_key=api_key)
        if result is None:
            typer.echo("Lancamento financeiro nao encontrado.")
            return
        typer.echo(format_output(result, output))
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception as exc:
        handle_error(exc)


@financial_app.command("installment")
def get_installment(
    installment_key: str = typer.Argument(help="Chave unica da parcela."),
    output: OutputFormat = typer.Option(
        OutputFormat.json, "--output", "-o", help="Formato: json|table|csv"
    ),
) -> None:
    """Retorna os dados de uma parcela pelo seu identificador.

    EXAMPLES:
      aegro financial installment abc123
      aegro financial installment abc123 --output table
    """
    try:
        _, api_key = require_farm()
        client = get_client()
        result = client.get(
            f"/pub/v1/installments/{validate_key(installment_key)}", api_key=api_key
        )
        if result is None:
            typer.echo("Parcela nao encontrada.")
            return
        typer.echo(format_output(result, output))
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception as exc:
        handle_error(exc)


@financial_app.command("installments")
def list_installments(
    operation_type: Optional[str] = typer.Option(
        None, "--operation-type", help="Tipo de operacao (REVENUE ou EXPENSE)."
    ),
    status: Optional[list[str]] = typer.Option(
        None, "--status", help="Status (PAID, NOT_PAID). Repetivel."
    ),
    due_date_start: Optional[str] = typer.Option(
        None, "--due-date-start", help="Data de vencimento inicial (YYYY-MM-DD)."
    ),
    due_date_end: Optional[str] = typer.Option(
        None, "--due-date-end", help="Data de vencimento final (YYYY-MM-DD)."
    ),
    bill_key: Optional[list[str]] = typer.Option(
        None, "--bill-key", help="Chave de lancamento (repetivel)."
    ),
    page: int = typer.Option(1, "--page", help="Numero da pagina."),
    output: OutputFormat = typer.Option(
        OutputFormat.json, "--output", "-o", help="Formato: json|table|csv"
    ),
) -> None:
    """Lista parcelas de lancamentos financeiros com filtros opcionais.

    EXAMPLES:
      aegro financial installments
      aegro financial installments --operation-type EXPENSE --status PAID
      aegro financial installments --due-date-start 2025-01-01 --due-date-end 2025-12-31
      aegro financial installments --bill-key b1 --bill-key b2 --page 2
    """
    try:
        _, api_key = require_farm()
        client = get_client()
        body: dict = {
            "requiredPageNumber": page,
            "maximumItemsPerPageCount": 50,
        }
        if operation_type is not None:
            body["operationType"] = operation_type
        if status:
            body["statuses"] = status
        if due_date_start is not None:
            body["dueDateStart"] = due_date_start
        if due_date_end is not None:
            body["dueDateEnd"] = due_date_end
        if bill_key:
            body["billKeys"] = bill_key
        result = client.post("/pub/v1/installments/filter", api_key=api_key, json_body=body)
        if result is None:
            typer.echo("Nenhuma parcela encontrada.")
            return
        typer.echo(format_output(result, output))
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception as exc:
        handle_error(exc)


@financial_app.command("create-installment")
def create_installment(
    bill_key: str = typer.Option(..., "--bill-key", help="Chave do lancamento financeiro."),
    bank_account_key: str = typer.Option(
        ..., "--bank-account-key", help="Chave da conta bancaria."
    ),
    due_date: str = typer.Option(..., "--due-date", help="Data de vencimento (YYYY-MM-DD)."),
    amount: float = typer.Option(..., "--amount", help="Valor da parcela."),
    currency: str = typer.Option("BRL", "--currency", help="Moeda (default: BRL)."),
    output: OutputFormat = typer.Option(
        OutputFormat.json, "--output", "-o", help="Formato: json|table|csv"
    ),
) -> None:
    """Cria uma nova parcela para um lancamento financeiro.

    EXAMPLES:
      aegro financial create-installment --bill-key b1 --bank-account-key ba1 --due-date 2025-06-01 --amount 1500.00
      aegro financial create-installment --bill-key b1 --bank-account-key ba1 --due-date 2025-06-01 --amount 1500.00 --currency USD
    """
    try:
        farm_name, api_key = require_farm()
        client = get_client()
        body: dict = {
            "billKey": bill_key,
            "bankAccountKey": bank_account_key,
            "dueDate": due_date,
            "amount": {"amount": amount, "currency": currency},
        }
        result = client.post("/pub/v1/installments", api_key=api_key, json_body=body)
        if result is None:
            typer.echo(f"Parcela criada na {farm_name}.")
        else:
            typer.echo(format_output(result, output))
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception as exc:
        handle_error(exc)


@financial_app.command("update-installment")
def update_installment(
    key: str = typer.Argument(help="Chave unica da parcela."),
    bill_key: str = typer.Option(..., "--bill-key", help="Chave do lancamento financeiro."),
    bank_account_key: str = typer.Option(
        ..., "--bank-account-key", help="Chave da conta bancaria."
    ),
    number: int = typer.Option(..., "--number", help="Numero sequencial da parcela."),
    due_date: str = typer.Option(..., "--due-date", help="Data de vencimento (YYYY-MM-DD)."),
    amount: float = typer.Option(..., "--amount", help="Valor da parcela."),
    currency: str = typer.Option("BRL", "--currency", help="Moeda (default: BRL)."),
    status: Optional[str] = typer.Option(None, "--status", help="Status (PAID ou NOT_PAID)."),
    realized_date: Optional[str] = typer.Option(
        None, "--realized-date", help="Data de pagamento (YYYY-MM-DD)."
    ),
    realized_amount: Optional[float] = typer.Option(
        None, "--realized-amount", help="Valor realizado."
    ),
    realized_currency: Optional[str] = typer.Option(
        None, "--realized-currency", help="Moeda do valor realizado."
    ),
    output: OutputFormat = typer.Option(
        OutputFormat.json, "--output", "-o", help="Formato: json|table|csv"
    ),
) -> None:
    """Atualiza uma parcela existente.

    EXAMPLES:
      aegro financial update-installment i1 --bill-key b1 --bank-account-key ba1 --number 1 --due-date 2025-06-01 --amount 2000.00
      aegro financial update-installment i1 --bill-key b1 --bank-account-key ba1 --number 1 --due-date 2025-06-01 --amount 2000.00 --status PAID --realized-date 2025-05-30
    """
    try:
        farm_name, api_key = require_farm()
        client = get_client()
        body: dict = {
            "key": key,
            "billKey": bill_key,
            "bankAccountKey": bank_account_key,
            "number": number,
            "dueDate": due_date,
            "amount": {"amount": amount, "currency": currency},
        }
        if status is not None:
            body["status"] = status
        if realized_date is not None:
            body["realizedDate"] = realized_date
        if realized_amount is not None:
            body["realizedAmount"] = {
                "amount": realized_amount,
                "currency": realized_currency or currency,
            }
        result = client.put(
            f"/pub/v1/installments/{validate_key(key)}",
            api_key=api_key,
            json_body=body,
        )
        if result is None:
            typer.echo(f"Parcela atualizada na {farm_name}.")
        else:
            typer.echo(format_output(result, output))
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception as exc:
        handle_error(exc)


@financial_app.command("delete-installment")
def delete_installment(
    key: str = typer.Argument(help="Chave unica da parcela."),
) -> None:
    """Exclui uma parcela pelo seu identificador.

    EXAMPLES:
      aegro financial delete-installment i1
    """
    try:
        farm_name, api_key = require_farm()
        client = get_client()
        client.delete(f"/pub/v1/installments/{validate_key(key)}", api_key=api_key)
        typer.echo(f"Parcela excluida da {farm_name}.")
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception as exc:
        handle_error(exc)


@financial_app.command("realize")
def realize_installments(
    key: list[str] = typer.Option(..., "--key", help="Chave da parcela (repetivel, obrigatorio)."),
    output: OutputFormat = typer.Option(
        OutputFormat.json, "--output", "-o", help="Formato: json|table|csv"
    ),
) -> None:
    """Realiza (paga) uma lista de parcelas de uma vez.

    EXAMPLES:
      aegro financial realize --key i1 --key i2
    """
    try:
        farm_name, api_key = require_farm()
        client = get_client()
        body: dict = {"list": key}
        result = client.post("/pub/v1/installments/realizeList", api_key=api_key, json_body=body)
        if result is None:
            typer.echo(f"Parcelas realizadas na {farm_name}.")
        else:
            typer.echo(format_output(result, output))
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception as exc:
        handle_error(exc)
