from __future__ import annotations

import json
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

purchase_requisitions_app = typer.Typer(help="Requisicoes de compra.")


def _parse_json(value: str, flag: str) -> list | dict:
    try:
        return json.loads(value)
    except json.JSONDecodeError as exc:
        typer.echo(f"{flag} contem JSON invalido: {exc}", err=True)
        raise SystemExit(4) from exc


def _parse_json_list(value: str, flag: str) -> list:
    parsed = _parse_json(value, flag)
    if not isinstance(parsed, list):
        typer.echo(f"{flag} deve ser uma lista JSON.", err=True)
        raise SystemExit(4)
    return parsed


@purchase_requisitions_app.command("get")
def get_requisition(
    key: str = typer.Argument(help="Chave unica da requisicao de compra."),
    output: OutputFormat = typer.Option(
        OutputFormat.json, "--output", "-o", help="Formato: json|table|csv"
    ),
) -> None:
    """Retorna os dados de uma requisicao de compra.

    EXAMPLES:
      aegro purchase-requisitions get purchaseRequisition::abc
    """
    try:
        _, api_key = require_farm()
        client = get_client()
        result = client.get(f"/pub/v1/purchase-requisitions/{validate_key(key)}", api_key=api_key)
        if result is None:
            typer.echo("Requisicao nao encontrada.")
            return
        typer.echo(format_output(result, output))
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception as exc:
        handle_error(exc)


@purchase_requisitions_app.command("list")
def list_requisitions(
    start_date: Optional[str] = typer.Option(
        None, "--start-date", help="Data de criacao inicial (YYYY-MM-DD)."
    ),
    end_date: Optional[str] = typer.Option(
        None, "--end-date", help="Data de criacao final (YYYY-MM-DD)."
    ),
    start_due_date: Optional[str] = typer.Option(
        None, "--start-due-date", help="Data de vencimento inicial (YYYY-MM-DD)."
    ),
    end_due_date: Optional[str] = typer.Option(
        None, "--end-due-date", help="Data de vencimento final (YYYY-MM-DD)."
    ),
    element_key: Optional[list[str]] = typer.Option(
        None, "--element-key", help="Chave de elemento (repetivel)."
    ),
    status: Optional[list[str]] = typer.Option(None, "--status", help="Status (repetivel)."),
    tag: Optional[list[str]] = typer.Option(None, "--tag", help="Tag (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 requisicoes de compra com filtros opcionais.

    EXAMPLES:
      aegro purchase-requisitions list
      aegro purchase-requisitions list --status OPEN --status APPROVED --start-date 2025-01-01
    """
    try:
        _, api_key = require_farm()
        client = get_client()
        body: dict = {
            "requiredPageNumber": page,
            "maximumItemsPerPageCount": 50,
        }
        if start_date is not None:
            body["startDate"] = start_date
        if end_date is not None:
            body["endDate"] = end_date
        if start_due_date is not None:
            body["startDueDate"] = start_due_date
        if end_due_date is not None:
            body["endDueDate"] = end_due_date
        if element_key:
            body["elementKeys"] = element_key
        if status:
            body["statuses"] = status
        if tag:
            body["tags"] = tag
        result = client.post(
            "/pub/v1/purchase-requisitions/filter", api_key=api_key, json_body=body
        )
        if result is None:
            typer.echo("Nenhuma requisicao encontrada.")
            return
        typer.echo(format_output(result, output))
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception as exc:
        handle_error(exc)


@purchase_requisitions_app.command("create")
def create_requisition(
    date: str = typer.Option(..., "--date", help="Data de criacao (YYYY-MM-DD)."),
    due_date: str = typer.Option(..., "--due-date", help="Data de vencimento (YYYY-MM-DD)."),
    status: str = typer.Option(
        ...,
        "--status",
        help="OPEN|IN_BUDGET|APPROVED|PURCHASE_ORDER_PAID|PURCHASE_ORDER_DELIVERED|REJECTED.",
    ),
    requisitioners: str = typer.Option(
        ..., "--requisitioners", help="Lista de requisitantes como JSON."
    ),
    inputs: str = typer.Option(..., "--inputs", help="Lista de insumos como JSON."),
    observations: Optional[str] = typer.Option(None, "--observations", help="Observacoes."),
    tag: Optional[list[str]] = typer.Option(None, "--tag", help="Tag (repetivel)."),
    output: OutputFormat = typer.Option(
        OutputFormat.json, "--output", "-o", help="Formato: json|table|csv"
    ),
) -> None:
    """Cria uma nova requisicao de compra.

    Os campos --requisitioners e --inputs seguem os schemas
    PurchaseRequisitionerPublicResource e PurchaseRequisitionInputPublicResource.

    EXAMPLES:
      aegro purchase-requisitions create --date 2025-06-01 --due-date 2025-06-15 \\
        --status OPEN --requisitioners '[{"userKey":"user::u1"}]' \\
        --inputs '[{"elementKey":"element::e1","quantity":10,"measuringUnit":"kg"}]'
    """
    try:
        farm_name, api_key = require_farm()
        client = get_client()
        body: dict = {
            "date": date,
            "dueDate": due_date,
            "status": status,
            "requisitioners": _parse_json_list(requisitioners, "--requisitioners"),
            "inputs": _parse_json_list(inputs, "--inputs"),
        }
        if observations is not None:
            body["observations"] = observations
        if tag:
            body["tags"] = tag
        result = client.post("/pub/v1/purchase-requisitions", api_key=api_key, json_body=body)
        if result is None:
            typer.echo(f"Requisicao criada na {farm_name}.")
        else:
            typer.echo(format_output(result, output))
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception as exc:
        handle_error(exc)


@purchase_requisitions_app.command("update")
def update_requisition(
    key: str = typer.Argument(help="Chave unica da requisicao de compra."),
    body_json: str = typer.Option(
        ...,
        "--body",
        help="Corpo completo como JSON (PurchaseRequisitionPublicResource).",
    ),
    output: OutputFormat = typer.Option(
        OutputFormat.json, "--output", "-o", help="Formato: json|table|csv"
    ),
) -> None:
    """Atualiza uma requisicao de compra existente (PUT completo).

    EXAMPLES:
      aegro purchase-requisitions update purchaseRequisition::abc --body '{"date":"2025-06-01",...}'
    """
    try:
        farm_name, api_key = require_farm()
        client = get_client()
        parsed = _parse_json(body_json, "--body")
        if not isinstance(parsed, dict):
            typer.echo("--body deve ser um objeto JSON.", err=True)
            raise SystemExit(4)
        result = client.put(
            f"/pub/v1/purchase-requisitions/{validate_key(key)}",
            api_key=api_key,
            json_body=parsed,
        )
        if result is None:
            typer.echo(f"Requisicao atualizada na {farm_name}.")
        else:
            typer.echo(format_output(result, output))
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception as exc:
        handle_error(exc)
