from __future__ import annotations

from datetime import date, datetime

from smartwallet.model import Category, Transaction


class BudgetFactory:
    @staticmethod
    def create_transaction(
        name: str,
        amount: str | float,
        trans_date: str | None = None,
    ) -> Transaction:
        if not name or not name.strip():
            raise ValueError("Transaction name cannot be empty.")

        try:
            value = float(amount)
        except (TypeError, ValueError) as exc:
            raise ValueError("Amount must be a number.") from exc

        if value == 0:
            raise ValueError("Transaction amount cannot be 0.")

        final_date = trans_date
        if not final_date:
            final_date = date.today().isoformat()
        else:
            try:
                datetime.fromisoformat(final_date)
            except ValueError as exc:
                raise ValueError("Invalid date format (expected YYYY-MM-DD).") from exc

        return Transaction(name=name, amount=value, transaction_date=final_date)

    @staticmethod
    def create_category(name: str) -> Category:
        if not name or not name.strip():
            raise ValueError("Category name cannot be empty.")

        return Category(name=name)

    @staticmethod
    def update_transaction(
        transaction: Transaction,
        name: str,
        amount: str | float,
        trans_date: str | None = None,
    ) -> None:
        if not name or not name.strip():
            raise ValueError("Transaction name cannot be empty.")

        try:
            value = float(amount)
        except (TypeError, ValueError) as exc:
            raise ValueError("Amount must be a number.") from exc

        if value == 0:
            raise ValueError("Transaction amount cannot be 0.")

        final_date = trans_date
        if not final_date:
            final_date = transaction.transaction_date
        else:
            try:
                datetime.fromisoformat(final_date)
            except ValueError as exc:
                raise ValueError("Invalid date format (expected YYYY-MM-DD).") from exc

        transaction.name = name
        transaction.amount = value
        transaction.transaction_date = final_date

    @staticmethod
    def update_category(category: Category, name: str) -> None:
        if not name or not name.strip():
            raise ValueError("Category name cannot be empty.")

        category.name = name
