# !/usr/bin/env python3

import datetime
import os

from garth.exc import GarthHTTPError

from garminconnect import (
    Garmin,
    GarminConnectAuthenticationError,
)


from prometheus_client import CollectorRegistry, push_to_gateway
from prometheus_client.core import GaugeMetricFamily

email = os.getenv("GARMIN_EMAIL")
password = os.getenv("GARMIN_PASSWORD")
tokenstore = os.getenv("GARMINTOKENS") or "~/.garminconnect"
tokenstore_base64 = os.getenv("GARMINTOKENS_BASE64") or "~/.garminconnect_base64"
gateway_address = os.getenv("PUSHGATEWAY_ADDRESS")

today = datetime.date.today()


def init_api(email=email, password=password):
    """Initialize Garmin API with your credentials."""

    try:
        print(
            f"Trying to login to Garmin Connect using token data from directory '{tokenstore}'...\n"
        )

        garmin = Garmin()
        garmin.login(tokenstore)
    except (FileNotFoundError, GarthHTTPError, GarminConnectAuthenticationError):
        # Session is expired. You'll need to log in again
        print(
            "Login tokens not present, login with your Garmin Connect credentials to generate them.\n"
            f"They will be stored in '{tokenstore}' for future use.\n"
        )
        garmin = Garmin(email=email, password=password, is_cn=False)
        garmin.login()
        # Save Oauth1 and Oauth2 token files to directory for next login
        garmin.garth.dump(tokenstore)
        print(
            f"Oauth tokens stored in '{tokenstore}' directory for future use. (first method)\n"
        )
        # Encode Oauth1 and Oauth2 tokens to base64 string and safe to file for next login (alternative way)
        token_base64 = garmin.garth.dumps()
        dir_path = os.path.expanduser(tokenstore_base64)
        with open(dir_path, "w") as token_file:
            token_file.write(token_base64)
        print(
            f"Oauth tokens encoded as base64 string and saved to '{dir_path}' file for future use. (second method)\n"
        )

    return garmin


class GarminCollector:
    def __init__(self):
        super().__init__()
        self.api = init_api()

    def collect(self):
        try:
            body = self.api.get_daily_weigh_ins(today.isoformat())["totalAverage"]
            metric_gauge = GaugeMetricFamily("body_composition", "Body composition and weight", labels=["metric"])
            for k in ["weight", "bmi", "bodyFat", "bodyWater", "boneMass", "muscleMass", "physiqueRating", "visceralFat"]:
                metric_gauge.add_metric([k], body[k])
        except Exception as e:
            print(f"Something went wrong while fetching body composition data\n{e}")

        yield metric_gauge


if __name__ == "__main__":
    registry = CollectorRegistry()
    registry.register(GarminCollector())

    push_to_gateway(gateway_address, job='garmin', registry=registry)