# Copyright 2021-2022 Teemu Ikonen
# SPDX-License-Identifier: GPL-3.0-only

import gi
import os

from datetime import datetime, timezone

gi.require_version('Gdk', '3.0')
from gi.repository import Gdk  # noqa: E402

gps_epoch = datetime(1980, 1, 6, 0, 0, tzinfo=timezone.utc)
now = datetime.now(timezone.utc)
one_week = 7 * 24 * 60 * 60
week_now = int((now.timestamp() - gps_epoch.timestamp()) / one_week)


def have_touchscreen():
    """Return True if the default seat of default display has touch capability
    """
    return bool(Gdk.Display.get_default_seat(
        Gdk.Display.get_default()).get_capabilities() & Gdk.SeatCapabilities.TOUCH)


def datetime_from_gpstime(week, millisecs, fix_week=False):
    """Return a datetime object formed from GPS week number and
    milliseconds from week start.

    If fix_week is True, set the bits above 10 in week number from
    current date, see
    https://en.wikipedia.org/wiki/GPS_week_number_rollover
    """
    if fix_week:
        week = (week & 0b1111111111) + ((week_now >> 10) << 10)
    return datetime.fromtimestamp(
        gps_epoch.timestamp() + week * one_week + (millisecs / 1000),
        timezone.utc)


def gpstime_from_datetime(dt):
    """Return a (gps_week, millisec) tuple from a datetime object"""
    if dt < gps_epoch:
        raise ValueError("Time cannot be less than GPS epoch")
    ts = dt.timestamp()
    epoch_ts = gps_epoch.timestamp()
    gps_week = int((ts - epoch_ts) / one_week)
    millisecs = 1000 * int(ts - epoch_ts - (gps_week * one_week))
    return gps_week, millisecs


def unique_filename(namestem, ext, timestamp=False):
    if timestamp:
        namestem += "-" + datetime.now().isoformat(
                          '_', 'seconds').replace(':', '.')
    name = None
    for count in ('~%d' % n if n > 0 else '' for n in range(100)):
        test = namestem + count + ext
        if os.path.exists(test):
            continue
        else:
            name = test
            break

    return name


def bearing_to_arrow(bearing):
    # Arrows in bearing order, with up arrow (north) repeating at the end
    arrows = [
        '\u2191',
        '\u2197',
        '\u2192',
        '\u2198',
        '\u2193',
        '\u2199',
        '\u2190',
        '\u2196',
        '\u2191',
    ]
    edges = list(22.5 + 45.0 * n for n in range(0, 8)) + [360.0]

    angle = bearing - (bearing // 360) * 360
    index = next(ind for (ind, e) in enumerate(edges) if angle < e)
    return arrows[index]
