from datetime import datetime, timezone
import numpy as np
import pandas as pd
import requests
from requests.exceptions import HTTPError
import warnings
import xarray as xr


def get_uid(attrs: dict) -> str:
    uid = attrs['AssetUniqueID']
    return uid


def get_deployment(deployment_da: xr.DataArray) -> int:
    deps = np.unique(deployment_da).tolist()
    if len(deps) == 1:
        dep = deps[0]
        return dep
    elif len(deps) > 1:
        raise ValueError('Multiple deployments identified in dataset.')


def get_subsite(attrs: dict) -> str:
    subsite = attrs['subsite']
    return subsite


def get_node(attrs: dict) -> str:
    node = attrs['node']
    return node


def get_instrument(attrs: dict) -> str:
    instrument = attrs['sensor']
    return instrument


def build_refdes(site, node, instrument):
    refdes = '-'.join([site, node, instrument])
    return refdes


def get_refdes(attrs: dict) -> str:
    site = get_subsite(attrs)
    node = get_node(attrs)
    instrument = get_instrument(attrs)
    refdes = build_refdes(site, node, instrument)
    return refdes


def build_refdes(site, node, instrument):
    refdes = '-'.join([site, node, instrument])
    return refdes


def _dt2micro(dt: datetime) -> int:
    """
    Convert a datetime object to microseconds since unix epoch.

    :param dt: A Python datetime.datetime object.
    :return: An integer representing the number of microseconds since 1970-01-01..
    """

    if isinstance(dt, datetime):
        microseconds = int(dt.replace(tzinfo=timezone.utc).timestamp() * 1000)
    elif isinstance(dt, xr.DataArray):
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            dt = pd.to_datetime(dt.values).to_pydatetime()
        microseconds = int(dt.replace(tzinfo=timezone.utc).timestamp() * 1000)
    return microseconds


def _micro2dt(microseconds: int) -> datetime:
    """
    Convert microseconds since unix epoch to datetime object.

    :param microseconds: The number of microseconds since 1970-01-01.
    :return: A datetime object.
    """

    if microseconds is None:
        return None
    else:
        seconds = microseconds/1000
        dt = datetime.fromtimestamp(seconds, tz = timezone.utc)
        return dt


def _dt2str(dt: datetime) -> str:
    """
    Convert a datetime object to an ISO8601 string.

    :param dt: A Python datetime object.
    :return: An ISO8601 string.
    """
    if dt is None:
        return None
    else:
        dtstr = dt.strftime('%Y-%m-%dT%H:%M:%SZ')
        return dtstr


def _get(url: str, params: dict | None = None) -> dict | list[dict]:
    """
    Make a GET request.
    If the response is okay, return the JSON content.
    If the response is not okay, raise an HTTPError.

    :param url: The URL for the GET request.
    :param params: Additional query parameters.
    :return: A dictionary or list of dictionaries containing the JSON data.
    """
    if params is None:
        response = requests.get(url)
    else:
        response = requests.get(url, params=params)
    if response.status_code == requests.codes.ok:
        json_data = response.json()
        return json_data
    else:
        raise HTTPError(f"{response.status_code}-{response.reason}: {response.text}")
