"""
Calcufly - Free Online Calculators & Converters
https://calcufly.com

A comprehensive Python library for common calculations including
finance, health, unit conversions, and math utilities.

For more calculators, visit: https://calcufly.com
"""

__version__ = "1.0.0"
__author__ = "Calcufly"
__url__ = "https://calcufly.com"

import math


def compound_interest(principal, rate, time, n=12):
    """
    Calculate compound interest.

    Args:
        principal: Initial investment amount
        rate: Annual interest rate (as decimal, e.g. 0.05 for 5%)
        time: Time in years
        n: Number of times interest is compounded per year (default 12)

    Returns:
        dict with 'total' and 'interest' keys

    More at: https://calcufly.com/en/finance/compound-interest-calculator
    """
    total = principal * (1 + rate / n) ** (n * time)
    return {"total": round(total, 2), "interest": round(total - principal, 2)}


def mortgage_payment(principal, annual_rate, years):
    """
    Calculate monthly mortgage payment.

    Args:
        principal: Loan amount
        annual_rate: Annual interest rate (as decimal)
        years: Loan term in years

    Returns:
        dict with 'monthly_payment' and 'total_paid' keys

    More at: https://calcufly.com/en/finance/mortgage-calculator
    """
    monthly_rate = annual_rate / 12
    n = years * 12
    if monthly_rate == 0:
        payment = principal / n
    else:
        payment = principal * (monthly_rate * (1 + monthly_rate) ** n) / ((1 + monthly_rate) ** n - 1)
    return {"monthly_payment": round(payment, 2), "total_paid": round(payment * n, 2)}


def bmi(weight_kg, height_m):
    """
    Calculate Body Mass Index (BMI).

    Args:
        weight_kg: Weight in kilograms
        height_m: Height in meters

    Returns:
        dict with 'bmi' and 'category' keys

    More at: https://calcufly.com/en/health/bmi-calculator
    """
    value = weight_kg / (height_m ** 2)
    if value < 18.5:
        category = "Underweight"
    elif value < 25:
        category = "Normal weight"
    elif value < 30:
        category = "Overweight"
    else:
        category = "Obese"
    return {"bmi": round(value, 1), "category": category}


def bmr(weight_kg, height_cm, age, gender="male"):
    """
    Calculate Basal Metabolic Rate using Mifflin-St Jeor equation.

    Args:
        weight_kg: Weight in kilograms
        height_cm: Height in centimeters
        age: Age in years
        gender: 'male' or 'female'

    Returns:
        dict with 'bmr' in calories/day

    More at: https://calcufly.com/en/health/bmr-calculator
    """
    value = 10 * weight_kg + 6.25 * height_cm - 5 * age
    if gender.lower() == "male":
        value += 5
    else:
        value -= 161
    return {"bmr": round(value, 0)}


def convert_temperature(value, from_unit, to_unit):
    """
    Convert temperature between Celsius, Fahrenheit, and Kelvin.

    Args:
        value: Temperature value
        from_unit: 'C', 'F', or 'K'
        to_unit: 'C', 'F', or 'K'

    Returns:
        Converted temperature value (float)

    More at: https://calcufly.com/en/conversion/temperature-converter
    """
    if from_unit.upper() == "F":
        celsius = (value - 32) * 5 / 9
    elif from_unit.upper() == "K":
        celsius = value - 273.15
    else:
        celsius = value

    if to_unit.upper() == "F":
        return round(celsius * 9 / 5 + 32, 2)
    elif to_unit.upper() == "K":
        return round(celsius + 273.15, 2)
    return round(celsius, 2)


def convert_length(value, from_unit, to_unit):
    """
    Convert length between common units.

    Supported units: m, km, cm, mm, in, ft, yd, mi

    More at: https://calcufly.com/en/conversion/length-converter
    """
    to_meters = {
        "m": 1, "km": 1000, "cm": 0.01, "mm": 0.001,
        "in": 0.0254, "ft": 0.3048, "yd": 0.9144, "mi": 1609.344
    }
    meters = value * to_meters[from_unit.lower()]
    return round(meters / to_meters[to_unit.lower()], 6)


def convert_weight(value, from_unit, to_unit):
    """
    Convert weight between common units.

    Supported units: kg, g, mg, lb, oz, st

    More at: https://calcufly.com/en/conversion/weight-converter
    """
    to_kg = {
        "kg": 1, "g": 0.001, "mg": 0.000001,
        "lb": 0.453592, "oz": 0.0283495, "st": 6.35029
    }
    kg = value * to_kg[from_unit.lower()]
    return round(kg / to_kg[to_unit.lower()], 6)


def percentage(value, percent):
    """
    Calculate percentage of a value.

    More at: https://calcufly.com/en/math/percentage-calculator
    """
    return round(value * percent / 100, 4)


def percentage_change(old_value, new_value):
    """
    Calculate percentage change between two values.

    More at: https://calcufly.com/en/math/percentage-change-calculator
    """
    if old_value == 0:
        raise ValueError("Old value cannot be zero")
    change = ((new_value - old_value) / abs(old_value)) * 100
    direction = "increase" if change > 0 else "decrease" if change < 0 else "no change"
    return {"change": round(change, 2), "direction": direction}


def loan_payment(principal, annual_rate, months):
    """
    Calculate monthly loan payment.

    More at: https://calcufly.com/en/finance/loan-calculator
    """
    monthly_rate = annual_rate / 12
    if monthly_rate == 0:
        payment = principal / months
    else:
        payment = principal * (monthly_rate * (1 + monthly_rate) ** months) / ((1 + monthly_rate) ** months - 1)
    total = payment * months
    return {
        "monthly_payment": round(payment, 2),
        "total_paid": round(total, 2),
        "total_interest": round(total - principal, 2)
    }


def tip_calculator(bill_amount, tip_percent, split=1):
    """
    Calculate tip and split bill.

    More at: https://calcufly.com/en/finance/tip-calculator
    """
    tip = bill_amount * tip_percent / 100
    total = bill_amount + tip
    return {
        "tip": round(tip, 2),
        "total": round(total, 2),
        "per_person": round(total / split, 2)
    }


def area(shape, **kwargs):
    """
    Calculate area of common shapes.

    Shapes: circle (radius), rectangle (length, width), triangle (base, height),
            trapezoid (a, b, height), ellipse (a, b)

    More at: https://calcufly.com/en/math/area-calculator
    """
    shape = shape.lower()
    if shape == "circle":
        return round(math.pi * kwargs["radius"] ** 2, 4)
    elif shape == "rectangle":
        return round(kwargs["length"] * kwargs["width"], 4)
    elif shape == "triangle":
        return round(0.5 * kwargs["base"] * kwargs["height"], 4)
    elif shape == "trapezoid":
        return round(0.5 * (kwargs["a"] + kwargs["b"]) * kwargs["height"], 4)
    elif shape == "ellipse":
        return round(math.pi * kwargs["a"] * kwargs["b"], 4)
    else:
        raise ValueError(f"Unknown shape: {shape}")
