import math
import tkinter as tk
from tkinter import messagebox, ttk


# Standard calculator functions
def add(a, b):
    return a + b


def subtract(a, b):
    return a - b


def multiply(a, b):
    return a * b


def divide(a, b):
    if b == 0:
        return "Error: Division by zero is not allowed."
    return a / b


def read_number(entry, field_name, *, minimum=None, strictly_positive=False):
    """Read and validate a finite number from an Entry widget."""
    value_text = entry.get().strip()
    if not value_text:
        raise ValueError(f"Please enter {field_name}.")

    try:
        value = float(value_text)
    except ValueError:
        raise ValueError(f"{field_name.capitalize()} must be a valid number.") from None

    if not math.isfinite(value):
        raise ValueError(f"{field_name.capitalize()} must be a finite number.")
    if strictly_positive and value <= 0:
        raise ValueError(f"{field_name.capitalize()} must be greater than zero.")
    if minimum is not None and value < minimum:
        raise ValueError(f"{field_name.capitalize()} cannot be less than {minimum:g}.")
    return value


def show_error(result_label, message):
    result_label.config(text=f"Error: {message}", foreground="#b91c1c")
    messagebox.showerror("Unable to Calculate", message)


def show_result(result_label, text):
    result_label.config(text=text, foreground="#166534")


def money(value):
    return f"{value:,.2f}"


def make_entry(parent, row, label):
    ttk.Label(parent, text=label).grid(row=row, column=0, sticky="w", padx=12, pady=6)
    entry = ttk.Entry(parent, width=24)
    entry.grid(row=row, column=1, sticky="ew", padx=12, pady=6)
    return entry


def make_result_label(parent, row):
    label = ttk.Label(
        parent,
        text="Enter the values and click Calculate.",
        style="Result.TLabel",
        wraplength=390,
        justify="left",
    )
    label.grid(row=row, column=0, columnspan=2, sticky="ew", padx=12, pady=(10, 12))
    return label


def create_standard_tab(notebook):
    tab = ttk.Frame(notebook, padding=28)
    notebook.add(tab, text="Standard Calculator")
    tab.columnconfigure(1, weight=1)

    ttk.Label(tab, text="Standard Calculator", style="Title.TLabel").grid(
        row=0, column=0, columnspan=2, pady=(0, 20)
    )
    first_entry = make_entry(tab, 1, "First number")
    second_entry = make_entry(tab, 2, "Second number")

    button_frame = ttk.Frame(tab)
    button_frame.grid(row=3, column=0, columnspan=2, sticky="ew", pady=12)
    button_frame.columnconfigure((0, 1), weight=1)

    result = make_result_label(tab, 4)

    def calculate(operation_name, operation):
        try:
            first = read_number(first_entry, "the first number")
            second = read_number(second_entry, "the second number")
            answer = operation(first, second)
            if isinstance(answer, str):
                show_error(result, "Division by zero is not allowed.")
            else:
                show_result(result, f"{operation_name} result: {answer:g}")
        except ValueError as error:
            show_error(result, str(error))

    operations = [
        ("Addition", add),
        ("Subtraction", subtract),
        ("Multiplication", multiply),
        ("Division", divide),
    ]
    for index, (name, function) in enumerate(operations):
        ttk.Button(
            button_frame,
            text=name,
            command=lambda n=name, f=function: calculate(n, f),
        ).grid(row=index // 2, column=index % 2, sticky="ew", padx=5, pady=5)

    def clear():
        first_entry.delete(0, tk.END)
        second_entry.delete(0, tk.END)
        result.config(
            text="Enter the values and choose an operation.",
            foreground="#374151",
        )
        first_entry.focus()

    ttk.Button(tab, text="Clear", command=clear).grid(
        row=5, column=0, columnspan=2, pady=6
    )
    first_entry.focus()


def create_profit_margin_tool(parent):
    frame = ttk.LabelFrame(parent, text="1. Profit and Margin", padding=8)
    frame.columnconfigure(1, weight=1)
    cost_entry = make_entry(frame, 0, "Cost price")
    selling_entry = make_entry(frame, 1, "Selling price")
    result = make_result_label(frame, 3)

    def calculate():
        try:
            cost = read_number(cost_entry, "the cost price", strictly_positive=True)
            selling = read_number(selling_entry, "the selling price", minimum=0)

            # Profit = selling price - cost price.
            profit = selling - cost
            # Margin uses selling price as its base; a zero selling price is undefined.
            if selling == 0:
                raise ValueError(
                    "Selling price must be greater than zero to calculate profit margin."
                )
            margin = profit / selling * 100
            # Markup uses cost price as its base.
            markup = profit / cost * 100
            show_result(
                result,
                f"Profit: {money(profit)}\n"
                f"Profit margin: {margin:.2f}%\n"
                f"Markup: {markup:.2f}%",
            )
        except ValueError as error:
            show_error(result, str(error))

    ttk.Button(frame, text="Calculate Profit and Margin", command=calculate).grid(
        row=2, column=0, columnspan=2, pady=6
    )
    return frame


def create_target_price_tool(parent):
    frame = ttk.LabelFrame(parent, text="2. Target Selling Price", padding=8)
    frame.columnconfigure(1, weight=1)
    cost_entry = make_entry(frame, 0, "Cost price")
    margin_entry = make_entry(frame, 1, "Desired profit margin (%)")
    result = make_result_label(frame, 3)

    def calculate():
        try:
            cost = read_number(cost_entry, "the cost price", minimum=0)
            margin = read_number(entry=margin_entry, field_name="the desired margin")
            if margin < 0 or margin >= 100:
                raise ValueError(
                    "Desired profit margin must be at least 0% and less than 100%."
                )

            # Selling price = cost / (1 - desired margin as a decimal).
            selling_price = cost / (1 - margin / 100)
            show_result(result, f"Required selling price: {money(selling_price)}")
        except ValueError as error:
            show_error(result, str(error))

    ttk.Button(frame, text="Calculate Target Price", command=calculate).grid(
        row=2, column=0, columnspan=2, pady=6
    )
    return frame


def create_discount_tool(parent):
    frame = ttk.LabelFrame(parent, text="3. Discount Calculator", padding=8)
    frame.columnconfigure(1, weight=1)
    price_entry = make_entry(frame, 0, "Original price")
    discount_entry = make_entry(frame, 1, "Discount (%)")
    result = make_result_label(frame, 3)

    def calculate():
        try:
            price = read_number(price_entry, "the original price", minimum=0)
            discount = read_number(discount_entry, "the discount percentage")
            if discount < 0 or discount > 100:
                raise ValueError("Discount percentage must be between 0% and 100%.")

            # Discount amount = original price × discount rate.
            discount_amount = price * discount / 100
            # Final price = original price - discount amount.
            final_price = price - discount_amount
            show_result(
                result,
                f"Discount amount: {money(discount_amount)}\n"
                f"Final price: {money(final_price)}",
            )
        except ValueError as error:
            show_error(result, str(error))

    ttk.Button(frame, text="Calculate Discount", command=calculate).grid(
        row=2, column=0, columnspan=2, pady=6
    )
    return frame


def create_vat_tool(parent):
    frame = ttk.LabelFrame(parent, text="4. VAT Calculator", padding=8)
    frame.columnconfigure(1, weight=1)

    vat_notebook = ttk.Notebook(frame)
    vat_notebook.grid(row=0, column=0, columnspan=2, sticky="nsew")

    exclusive_tab = ttk.Frame(vat_notebook, padding=6)
    inclusive_tab = ttk.Frame(vat_notebook, padding=6)
    exclusive_tab.columnconfigure(1, weight=1)
    inclusive_tab.columnconfigure(1, weight=1)
    vat_notebook.add(exclusive_tab, text="Add VAT")
    vat_notebook.add(inclusive_tab, text="Remove VAT")

    price_entry = make_entry(exclusive_tab, 0, "Price before VAT")
    vat_entry = make_entry(exclusive_tab, 1, "VAT (%)")
    add_result = make_result_label(exclusive_tab, 3)

    def add_vat():
        try:
            price = read_number(price_entry, "the price", minimum=0)
            vat_rate = read_number(vat_entry, "the VAT percentage", minimum=0)

            # VAT amount = net price × VAT rate.
            vat_amount = price * vat_rate / 100
            # VAT-inclusive total = net price + VAT amount.
            total = price + vat_amount
            show_result(
                add_result,
                f"VAT amount: {money(vat_amount)}\n"
                f"Total including VAT: {money(total)}",
            )
        except ValueError as error:
            show_error(add_result, str(error))

    ttk.Button(exclusive_tab, text="Add VAT", command=add_vat).grid(
        row=2, column=0, columnspan=2, pady=6
    )

    inclusive_entry = make_entry(inclusive_tab, 0, "VAT-inclusive price")
    inclusive_vat_entry = make_entry(inclusive_tab, 1, "VAT (%)")
    remove_result = make_result_label(inclusive_tab, 3)

    def remove_vat():
        try:
            inclusive_price = read_number(
                inclusive_entry, "the VAT-inclusive price", minimum=0
            )
            vat_rate = read_number(
                inclusive_vat_entry, "the VAT percentage", minimum=0
            )

            # Net price = inclusive price / (1 + VAT rate).
            divisor = 1 + vat_rate / 100
            if divisor == 0:
                raise ValueError("The VAT rate creates an invalid zero divisor.")
            net_price = inclusive_price / divisor
            # VAT amount is the difference between inclusive and net prices.
            vat_amount = inclusive_price - net_price
            show_result(
                remove_result,
                f"Price before VAT: {money(net_price)}\n"
                f"VAT amount: {money(vat_amount)}",
            )
        except ValueError as error:
            show_error(remove_result, str(error))

    ttk.Button(inclusive_tab, text="Remove VAT", command=remove_vat).grid(
        row=2, column=0, columnspan=2, pady=6
    )
    return frame


def create_break_even_tool(parent):
    frame = ttk.LabelFrame(parent, text="5. Break-Even Calculator", padding=8)
    frame.columnconfigure(1, weight=1)
    fixed_entry = make_entry(frame, 0, "Fixed costs")
    selling_entry = make_entry(frame, 1, "Selling price per unit")
    variable_entry = make_entry(frame, 2, "Variable cost per unit")
    result = make_result_label(frame, 4)

    def calculate():
        try:
            fixed_costs = read_number(fixed_entry, "the fixed costs", minimum=0)
            selling_price = read_number(
                selling_entry, "the selling price per unit", minimum=0
            )
            variable_cost = read_number(
                variable_entry, "the variable cost per unit", minimum=0
            )
            contribution = selling_price - variable_cost
            if contribution <= 0:
                raise ValueError(
                    "Selling price per unit must be greater than variable cost per unit."
                )

            # Break-even units = fixed costs / contribution earned per unit.
            exact_quantity = fixed_costs / contribution
            # Whole products cannot be sold fractionally, so round up to the next unit.
            break_even_quantity = math.ceil(exact_quantity)
            show_result(
                result,
                f"Break-even quantity: {break_even_quantity:,} unit(s)\n"
                f"Exact break-even point: {exact_quantity:,.2f} units",
            )
        except ValueError as error:
            show_error(result, str(error))

    ttk.Button(frame, text="Calculate Break-Even", command=calculate).grid(
        row=3, column=0, columnspan=2, pady=6
    )
    return frame


def create_business_tab(notebook):
    tab = ttk.Frame(notebook, padding=12)
    notebook.add(tab, text="Business Calculator")
    tab.columnconfigure((0, 1), weight=1, uniform="business")

    ttk.Label(tab, text="Business Calculator", style="Title.TLabel").grid(
        row=0, column=0, columnspan=2, pady=(0, 10)
    )

    profit_frame = create_profit_margin_tool(tab)
    target_frame = create_target_price_tool(tab)
    discount_frame = create_discount_tool(tab)
    vat_frame = create_vat_tool(tab)
    break_even_frame = create_break_even_tool(tab)

    profit_frame.grid(row=1, column=0, sticky="nsew", padx=6, pady=6)
    target_frame.grid(row=1, column=1, sticky="nsew", padx=6, pady=6)
    discount_frame.grid(row=2, column=0, sticky="nsew", padx=6, pady=6)
    vat_frame.grid(row=2, column=1, sticky="nsew", padx=6, pady=6)
    break_even_frame.grid(row=3, column=0, columnspan=2, sticky="ew", padx=6, pady=6)


def main():
    root = tk.Tk()
    root.title("Business Calculator")
    root.geometry("1000x850")
    root.minsize(900, 760)
    root.configure(bg="#f3f4f6")

    style = ttk.Style(root)
    if "clam" in style.theme_names():
        style.theme_use("clam")
    style.configure("TFrame", background="#f3f4f6")
    style.configure("Title.TLabel", font=("Segoe UI", 22, "bold"))
    style.configure("TLabel", font=("Segoe UI", 10))
    style.configure("TLabelframe.Label", font=("Segoe UI", 11, "bold"))
    style.configure("TButton", font=("Segoe UI", 10), padding=7)
    style.configure(
        "Result.TLabel",
        background="#ffffff",
        foreground="#374151",
        padding=10,
        relief="solid",
        borderwidth=1,
    )

    notebook = ttk.Notebook(root)
    notebook.pack(fill="both", expand=True, padx=12, pady=12)
    create_standard_tab(notebook)
    create_business_tab(notebook)

    root.mainloop()


if __name__ == "__main__":
    main()
