#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include <keks/dectai.h>
#include <keks/err.h>

#include "hex.h"
#include "printai.h"

static void
printDT(const struct tm *tm, const struct timespec *tv, const size_t len)
{
    {
        char human[20] = {0};
        strftime(human, sizeof human, "%Y-%m-%d %H:%M:%S", tm);
        fputs(human, stdout);
    }
    if (len == 12) {
        fprintf(stdout, ".%09zu", tv->tv_nsec);
    }
}

enum KEKSErr
PrintTAI64(const unsigned char *buf, const size_t len)
{
    char *hex = NULL;
    if (len == 16) {
        hex = HexEnc(buf, len);
        fprintf(stdout, "TAI64NA(%s)\n", hex);
        free(hex);
        return KEKSErrNo;
    }
    switch (len) {
    case 8:
        fputs("TAI64(", stdout);
        break;
    case 12:
        fputs("TAI64N(", stdout);
        break;
    default:
        break;
    }
    struct timespec tv;
    enum KEKSErr err = KEKSTAI64ToTimespec(&tv, buf, len);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wswitch-enum"
    switch (err) {
#pragma clang diagnostic pop
    case KEKSErrNo:
        break;
    case KEKSErrTAI64InPast:
        hex = HexEnc(buf, len);
        fprintf(stdout, "in past: %s)\n", hex);
        free(hex);
        return KEKSErrNo;
    default:
        return err;
    }
    time_t t = tv.tv_sec;
    struct tm *tm = localtime(&t);
    if (tm == NULL) {
        hex = HexEnc(buf, len);
        fprintf(stdout, "TAI unrepresentable: %s)\n", hex);
        free(hex);
        return KEKSErrNo;
    }
    printDT(tm, &tv, len);
    fputs(" TAI, ", stdout);
    err = KEKSTimespecToUTC(&tv);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wswitch-enum"
    switch (err) {
#pragma clang diagnostic pop
    case KEKSErrNo:
        break;
    case KEKSErrTAI64InPast:
        fputs("UTC in past)", stdout);
        return KEKSErrNo;
    case KEKSErrTAI64IsLeap:
        fputs("leap)", stdout);
        return KEKSErrNo;
    default:
        return err;
    }
    t = tv.tv_sec;
    tm = localtime(&t);
    if (tm == NULL) {
        fputs("UTC unrepresentable)", stdout);
        return KEKSErrNo;
    }
    printDT(tm, &tv, len);
    fputs(" UTC)\n", stdout);
    return KEKSErrNo;
}
