"""
MCP Simple Timeserver - Local (stdio) variant.

This server provides time-related tools to AI assistants via the
Model Context Protocol (MCP) using stdio transport.
"""
from datetime import datetime
from importlib.metadata import version

from fastmcp import FastMCP

from .core import (
    DEFAULT_NTP_SERVER,
    utc_time_result,
    current_time_result,
    time_distance_result,
    get_holidays_result,
    is_holiday_result,
)


# Get package version dynamically from pyproject.toml via importlib.metadata
_version = version("mcp-simple-timeserver")

app = FastMCP("mcp-simple-timeserver", version=_version)


# Note: in this context the docstrings are meant for the client AI
# to understand the tools and their purpose.

@app.tool(
    annotations={
        "title": "Get Local Time and Timezone",
        "readOnlyHint": True
    }
)
def get_local_time() -> str:
    """
    Returns the current local time and timezone information from your local machine.
    This helps you understand what time it is for the user you're assisting.
    """
    local_time = datetime.now()
    timezone = str(local_time.astimezone().tzinfo)
    formatted_time = local_time.strftime("%Y-%m-%d %H:%M:%S")
    day_of_week = local_time.strftime("%A")
    return f"Current Time: {formatted_time}\nDay: {day_of_week}\nTimezone: {timezone}"


@app.tool(
    annotations={
        "title": "Get UTC Time from an NTP Server",
        "readOnlyHint": True
    }
)
def get_utc(server: str = DEFAULT_NTP_SERVER) -> str:
    """
    Returns accurate UTC time from an NTP server.
    This provides a universal time reference regardless of local timezone.

    :param server: NTP server address (default: pool.ntp.org)
    """
    return utc_time_result(server)


@app.tool(
    annotations={
        "title": "Get Current Time with Optional Location and Calendar Systems",
        "readOnlyHint": True
    }
)
def get_current_time(
    calendar: str = "",
    timezone: str = "",
    country: str = "",
    city: str = ""
) -> str:
    """
    Returns current time, optionally localized to a specific location or timezone,
    with optional conversion to additional calendar systems.

    LOCATION PARAMETERS (use one, priority: timezone > city > country):

    :param city: City name (PRIMARY USE CASE). Examples: "Warsaw", "Tokyo", "New York"
        Resolves city to timezone automatically. Best for most queries.

    :param country: Country name or code. Examples: "Poland", "JP", "United States"
        Falls back to capital/major city timezone. Use when city is unknown.

    :param timezone: Direct IANA timezone or UTC offset. Examples: "Europe/Warsaw", "+05:30"
        Escape hatch for precise control. Use when you know the exact timezone.

    When a location is provided, the response includes:
    - Local time at that location
    - Timezone name and abbreviation (e.g., "Europe/Warsaw (CET)")
    - UTC offset (e.g., "+01:00")
    - DST status (Yes/No)
    - UTC time for reference

    When NO location is provided, returns UTC time only (original behavior).

    CALENDAR PARAMETER:

    :param calendar: Comma-separated list of additional calendars/formats.
        Valid values (case-insensitive):
        - "unix" - Unix timestamp (seconds since 1970-01-01)
        - "isodate" - ISO 8601 week date (YYYY-Www-D)
        - "hijri" - Islamic/Hijri lunar calendar
        - "japanese" - Japanese Era calendar (English and Kanji)
        - "persian" - Persian/Jalali calendar (English and Farsi)
        - "hebrew" - Hebrew/Jewish calendar (English and Hebrew script)

        Calendars are calculated for the LOCAL time when location is specified.

    EXAMPLES:
    - get_current_time(city="Warsaw") - Time in Warsaw with timezone info
    - get_current_time(city="Tokyo", calendar="japanese") - Tokyo time with Japanese calendar
    - get_current_time(timezone="+05:30") - Time at UTC+5:30 offset
    - get_current_time() - UTC time only (no location)

    Uses accurate time from NTP server when available.
    Invalid locations fall back to UTC with a helpful message.
    """
    return current_time_result(calendar, timezone, country, city)


@app.tool(
    annotations={
        "title": "Calculate Time/Date Distance",
        "readOnlyHint": True
    }
)
def calculate_time_distance(
    from_date: str = "now",
    to_date: str = "now",
    unit: str = "auto",
    timezone: str = "",
    city: str = "",
    country: str = "",
    business_days: bool = False,
    exclude_holidays: bool = False
) -> str:
    """
    Calculate the duration/distance between two dates or datetimes.
    Use this tool for countdowns, elapsed time calculations, or scheduling queries.

    :param from_date: Start date in ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS) or "now".
        Examples: "2025-01-15", "2025-01-15T09:30:00", "now"

    :param to_date: End date in ISO 8601 format or "now".
        Examples: "2025-12-31", "2025-06-01T17:00:00", "now"

    :param unit: Output format for the distance. Options:
        - "auto" (default) - Human-readable breakdown (e.g., "15 days, 3 hours, 45 minutes")
        - "days" - Decimal days (e.g., "15.50 days")
        - "weeks" - Decimal weeks (e.g., "2.21 weeks")
        - "hours" - Decimal hours (e.g., "372.00 hours")
        - "minutes" - Decimal minutes (e.g., "22320.00 minutes")
        - "seconds" - Total seconds (e.g., "1339200 seconds")

    LOCATION PARAMETERS (optional, same as get_current_time):

    :param city: City name for timezone context. Examples: "Warsaw", "Tokyo", "New York"
    :param country: Country name or code. Examples: "Poland", "JP"
    :param timezone: Direct IANA timezone or UTC offset. Examples: "Europe/Warsaw", "+05:30"

    Location affects how dates without explicit timezone are interpreted.
    Priority: timezone > city > country. If none provided, UTC is used.

    OUTPUT FORMAT:
    - Distance: The calculated duration
    - Human readable: Simplified summary (when unit="auto")
    - Direction: "future" if to_date > from_date, "past" if to_date < from_date
    - From/To: The parsed datetime values
    - UTC Reference: Both times converted to UTC

    BUSINESS DAYS MODE (optional):

    :param business_days: Count only business days (Mon-Fri), excluding weekends. Default: False.
        When True, returns business day count instead of elapsed-time duration.
        Time-of-day is ignored; dates are counted as full days (inclusive endpoints).
        The `unit` parameter is ignored in this mode.

    :param exclude_holidays: Also exclude public holidays. Default: False.
        Only effective when business_days=True.
        Requires country or city parameter to determine which holidays to exclude.
        If country cannot be determined, proceeds with weekend-only exclusion.

    Example: "How many business days until project deadline?"
        from_date="now", to_date="2026-03-15", business_days=True, country="Poland"

    COMMON USE CASES:
    - "How many days until Dec 31?" → from_date="now", to_date="2025-12-31"
    - "How long since Jan 1?" → from_date="2025-01-01", to_date="now"
    - "Duration between two dates" → from_date="2025-01-01", to_date="2025-03-15"

    NOTE: If both parameters are the same (e.g., both "now"), returns an error message.
    Uses accurate NTP time when "now" is specified.
    """
    return time_distance_result(
        from_date,
        to_date,
        unit,
        timezone,
        country,
        city,
        business_days,
        exclude_holidays
    )


@app.tool(
    annotations={
        "title": "Get Holidays for a Country",
        "readOnlyHint": True
    }
)
def get_holidays(
    country: str,
    year: int = 0,
    include_school_holidays: bool = False
) -> str:
    """
    Get a list of public holidays (and optionally school holidays) for a country and year.
    Use this tool when the user asks about holidays, days off, or vacation periods.

    :param country: Country name or ISO code (required).
        Examples: "Poland", "PL", "United States", "US", "Germany", "DE"
        Supports common aliases like "UK" for United Kingdom.

    :param year: Year to get holidays for (optional).
        Defaults to current year if not specified or 0.
        Examples: 2026, 2027

    :param include_school_holidays: Whether to include school vacation periods (optional).
        Default is False. Set to True to see school holidays.
        School holidays are only available for ~36 countries (mostly European).
        School holidays may vary by region (e.g., different dates for different states/provinces).

    OUTPUT FORMAT:
    - Public holidays: Date, name (with local name if different)
    - School holidays (if requested): Date range, name, regions affected

    EXAMPLES:
    - get_holidays(country="Poland") - All public holidays in Poland this year
    - get_holidays(country="DE", year=2026) - German holidays for 2026
    - get_holidays(country="Poland", include_school_holidays=True) - Polish holidays + school vacations

    NOTE: Public holiday data is available for ~119 countries.
    School holiday data is available for ~36 countries (mostly European).
    """
    # Convert year=0 to None for the core function (means "use current year")
    actual_year = year if year > 0 else None
    return get_holidays_result(country, actual_year, include_school_holidays)


@app.tool(
    annotations={
        "title": "Check if Date is a Holiday",
        "readOnlyHint": True
    }
)
def is_holiday(
    country: str = "",
    date: str = "",
    city: str = ""
) -> str:
    """
    Check if a specific date is a holiday in a given country or city.
    Use this tool to quickly verify if a particular day is a public or school holiday.

    LOCATION PARAMETERS (use at least one):

    :param country: Country name or ISO code.
        Examples: "Poland", "PL", "United States", "US"

    :param city: City name (PRIMARY USE CASE for regional holidays).
        Examples: "Warsaw", "Krakow", "Berlin", "Munich"
        When specified, automatically detects country and region for accurate
        school holiday filtering (e.g., school holidays vary by Polish voivodeship).

    :param date: Date to check in ISO format YYYY-MM-DD (optional).
        Defaults to today if not specified.
        Examples: "2026-01-01", "2026-12-25"

    OUTPUT FORMAT:
    - Yes/No indication if the date is a public holiday
    - Holiday name(s) if it is a holiday
    - School holiday information filtered to the specific region (if city provided)

    EXAMPLES:
    - is_holiday(city="Warsaw", date="2026-01-19") - Check school holidays in Warsaw
    - is_holiday(city="Krakow") - Check if today is a holiday in Krakow
    - is_holiday(country="Poland", date="2026-01-01") - Check New Year's Day in Poland
    - is_holiday(country="Germany", date="2026-12-25") - Check Christmas Day in Germany

    NOTE: Using city parameter provides region-specific school holiday info.
    School holidays vary by region in many countries (e.g., Polish voivodeships,
    German Bundesländer). Only ~36 countries have school holiday data available.
    """
    # Convert empty strings to appropriate values for the core function
    actual_date = date if date else None
    return is_holiday_result(country, actual_date, city)


if __name__ == "__main__":
    app.run()
