/*
 * util_date.c - 일자/영업일 유틸리티 (plain C, 공유)
 */
#include "acq_util.h"

#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <time.h>

static int is_all_digit(const char *s, int len)
{
    int i;
    for (i = 0; i < len; i++)
        if (!isdigit((unsigned char)s[i]))
            return 0;
    return 1;
}

static int to_int(const char *s, int len)
{
    int i, v = 0;
    for (i = 0; i < len; i++)
        v = v * 10 + (s[i] - '0');
    return v;
}

static int days_in_month(int y, int m)
{
    static const int d[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    if (m < 1 || m > 12)
        return 0;
    if (m == 2) {
        int leap = (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
        return leap ? 29 : 28;
    }
    return d[m - 1];
}

int date_is_valid(const char *yyyymmdd)
{
    int y, m, d;
    if (!yyyymmdd || strlen(yyyymmdd) < 8)
        return 0;
    if (!is_all_digit(yyyymmdd, 8))
        return 0;
    y = to_int(yyyymmdd, 4);
    m = to_int(yyyymmdd + 4, 2);
    d = to_int(yyyymmdd + 6, 2);
    if (y < 1900 || y > 2999) return 0;
    if (m < 1 || m > 12) return 0;
    if (d < 1 || d > days_in_month(y, m)) return 0;
    return 1;
}

int date_weekday(const char *yyyymmdd)
{
    static const int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
    int y, m, d;
    if (!date_is_valid(yyyymmdd))
        return -1;
    y = to_int(yyyymmdd, 4);
    m = to_int(yyyymmdd + 4, 2);
    d = to_int(yyyymmdd + 6, 2);
    if (m < 3)
        y -= 1;
    return (y + y / 4 - y / 100 + y / 400 + t[m - 1] + d) % 7;
}

int date_is_weekend(const char *yyyymmdd)
{
    int w = date_weekday(yyyymmdd);
    return (w == 0 || w == 6) ? 1 : 0;
}

static void add_one_day(const char *in, char *out)
{
    int y = to_int(in, 4);
    int m = to_int(in + 4, 2);
    int d = to_int(in + 6, 2);
    d++;
    if (d > days_in_month(y, m)) {
        d = 1; m++;
        if (m > 12) { m = 1; y++; }
    }
    snprintf(out, 9, "%04d%02d%02d", y, m, d);
}

int date_next_business(const char *yyyymmdd, char *out)
{
    char cur[9];
    int guard = 0;
    if (!date_is_valid(yyyymmdd) || !out)
        return -1;
    memcpy(cur, yyyymmdd, 8);
    cur[8] = '\0';
    do {
        add_one_day(cur, cur);
        if (++guard > 14)
            return -1;
    } while (date_is_weekend(cur));
    memcpy(out, cur, 8);
    out[8] = '\0';
    return 0;
}

void date_today(char *out)
{
    time_t     now = time(NULL);
    struct tm  tmv;
    localtime_r(&now, &tmv);
    strftime(out, 9, "%Y%m%d", &tmv);
}
