import logging
from typing import Optional
from zoneinfo import ZoneInfo
from django.utils import timezone
from datetime import datetime, tzinfo, timedelta, timezone as dt_timezone


logger = logging.getLogger(__name__)
DEFAULT_TIME_ZONE = "America/Los_Angeles"
PACIFIC_TZ = ZoneInfo(DEFAULT_TIME_ZONE)


def to_pacific(dt: datetime) -> Optional[datetime]:
    """
    Convert datetime to Pacific Time safely.
    If already Pacific, return as-is.
    """
    if not dt:
        return None

    # If naive → assume UTC
    if timezone.is_naive(dt):
        dt = timezone.make_aware(dt, dt_timezone.utc)

    return dt.astimezone(PACIFIC_TZ)


def pacific_now():
    """
    Get the current Pacific time safely.
    """
    return timezone.now().astimezone(PACIFIC_TZ)


def format_datetime(dt):
    """
    Format datetime into date and time strings.
    1. Date: "Jan, 15 2026"
    2. Time: "03:30 PM"
    """
    if dt is None:
        return None

    return (
        dt.strftime("%b, %d %Y"),   # Jan, 15 2026
        dt.strftime("%I:%M %p"),
    )


def iso_utc_z(dt: datetime) -> Optional[str]:
    if not dt:
        return None

    if timezone.is_naive(dt):
        dt = timezone.make_aware(dt, dt_timezone.utc)

    dt = dt.astimezone(dt_timezone.utc)
    return dt.isoformat(timespec="microseconds").replace("+00:00", "Z")


def to_utc(dt_str: str, time_zone_info: tzinfo) -> datetime:
    """
    Convert a datetime string to a timezone-aware UTC datetime.
    """
    try:
        dt = datetime.fromisoformat(dt_str)
    except ValueError:
        raise ValueError(f"Invalid datetime format: {dt_str}")

    if timezone.is_naive(dt):
        dt = timezone.make_aware(dt, time_zone_info)

    return dt.astimezone(dt_timezone.utc)


def dt_to_utc(dt: datetime, time_zone_info: tzinfo) -> datetime:

    if timezone.is_naive(dt):
        dt = timezone.make_aware(dt, time_zone_info)

    return dt.astimezone(dt_timezone.utc)


def dt_str_to_iso(dt_str: str) -> Optional[datetime]:
    """
    Convert a datetime string to an ISO 8601 format.
    """

    return datetime.fromisoformat(dt_str) if isinstance(dt_str, str) else None


def smart_parse_datetime(dt_str: str):
    try:
        # Try ISO first
        return datetime.fromisoformat(dt_str)
    except ValueError as exc:
        # Try human-readable format
        logger.warning(f"smart parse first exception {exc}")

        # Normalize AM/PM to uppercase and add space if missing
        normalized = (
            dt_str
            .replace("am", " AM")
            .replace("pm", " PM")
            .replace("AM", " AM")
            .replace("PM", " PM")
        )
        return datetime.strptime(
            normalized,
            "%A, %B %d, %Y at %I:%M %p"
        )

n = """
from utils.timezone_utils import (
    to_utc, dt_str_to_iso,
    tz_info_from_offset,
    smart_parse_datetime,
    dt_to_utc
)

service = None
booking_type = (service or "").strip().lower() or "oil change"

c = smart_parse_datetime("2024-06-14 10:30:00")
d = smart_parse_datetime("2026-01-27T13:00:00")
e = smart_parse_datetime("Wednesday, January 28, 2026 at 8:00am")
print(c)
print(c)
print(e)
"""

def str_to_dt(dt_val) -> Optional[datetime]:
    if isinstance(dt_val, datetime):
        return dt_val
    if isinstance(dt_val, str):
        return datetime.fromisoformat(dt_val)
    return None


def tz_info_from_offset(
    offset: Optional[str],
    fallback_zone: str = DEFAULT_TIME_ZONE,
):
    """
    Convert timezone offset string like '-8', '+5.5' to tz-info.
    Falls back to ZoneInfo if offset is missing or invalid.
    """
    if not offset:
        return ZoneInfo(fallback_zone)

    try:
        hours = float(offset)
        seconds = int(hours * 3600)
        return dt_timezone(timedelta(seconds=seconds))
    except (ValueError, TypeError):
        return ZoneInfo(fallback_zone)


def get_company_time(company):
    """
    Returns the current datetime of company's timezone.
    """

    company_tz = ZoneInfo(company.timezone)
    return timezone.now().astimezone(company_tz)


def get_current_company_time(user):
    """
    Returns the current datetime in the active company's timezone.
    """
    if not hasattr(user, 'active_company') or not user.active_company:
        return timezone.now()

    return get_company_time(user.active_company)
