package utils

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"time"
)

// GenerateDateRangeAzure generate a time range string like 20240801-20240831 for a timestamp
func GenerateDateRangeAzure(timestamp int64) string {
	t := time.Unix(timestamp, 0).UTC()
	year, month, _ := t.Date()
	firstDay := time.Date(year, month, 1, 0, 0, 0, 0, t.UTC().Location())
	lastDay := firstDay.AddDate(0, 1, -1)
	startDate := firstDay.Format("20060102")
	endDate := lastDay.Format("20060102")
	return fmt.Sprintf("%s-%s", startDate, endDate)
}

// GenerateDateRangeAWS generate a time range string like 20240801-20240901 for a timestamp
func GenerateDateRangeAWS(timestamp int64) string {
	t := time.Unix(timestamp, 0).UTC()
	year, month, _ := t.Date()
	firstDay := time.Date(year, month, 1, 0, 0, 0, 0, t.UTC().Location())
	lastDay := firstDay.AddDate(0, 1, 0)
	startDate := firstDay.Format("20060102")
	endDate := lastDay.Format("20060102")
	return fmt.Sprintf("%s-%s", startDate, endDate)
}

// GenerateDailyDate generates a day time string like 20240801 for a timestamp
func GenerateDailyDate(timestamp int64) string {
	t := time.Unix(timestamp, 0).UTC()
	return t.Format("20060102")
}

// GenerateDailyDate generates a day time string like 08/12/2024 for a timestamp
func GenerateBillingDate(timestamp int64) string {
	t := time.Unix(timestamp, 0).UTC()
	return t.Format("01/02/2006")
}

// GenerateCheckMonth generate a time monthly string like 202408 for a timestamp
func GenerateCheckMonth(timestamp int64) string {
	t := time.Unix(timestamp, 0).UTC()
	year, month, _ := t.Date()
	firstDay := time.Date(year, month, 1, 0, 0, 0, 0, t.UTC().Location())
	startDate := firstDay.Format("200601")
	return startDate
}

// GenerateBillingDateForGCP generates a day time string like 2024-08-12 for a timestamp
func GenerateBillingDateForGCP(timestamp int64) string {
	t := time.Unix(timestamp, 0).UTC()
	return t.Format("2006-01-02")
}

// EnsurePath ensure the path exists, if not create it
func EnsurePath(path string) error {
	info, err := os.Stat(path)
	if os.IsNotExist(err) {
		err = os.MkdirAll(path, os.ModePerm)
		if err != nil {
			return err
		}
	} else if err != nil {
		return err
	} else if !info.IsDir() {
		return errors.New("subpath exists but is not a directory")
	}
	return nil
}

func EnsureCache(cachepath string, perfix string) (string, error) {
	absCachePath, err := filepath.Abs(filepath.Join(cachepath, perfix))
	if err != nil {
		return "", err
	}
	err = EnsurePath(absCachePath)
	if err != nil {
		return "", err
	}
	err = CleanCache(absCachePath)
	if err != nil {
		return "", err
	}
	return absCachePath, err
}

func CleanCache(abspath string) error {
	dir, err := os.ReadDir(abspath)
	if err != nil {
		return err
	}
	for _, d := range dir {
		//for debug purpose, we do not remove the cache
		fmt.Println("remove cache", d.Name())
		os.RemoveAll(filepath.Join([]string{abspath, d.Name()}...))
	}
	return nil
}

func IsNumeric(s string) bool {
	re := regexp.MustCompile(`^\d+$`)
	return re.MatchString(s)
}

// GenerateHourDimension generates hour dimension string (YYYYMMDDHH) for a given timestamp
func GenerateHourDimension(timestamp int64) string {
	t := time.Unix(timestamp, 0).UTC()
	return fmt.Sprintf("%04d%02d%02d%02d", t.Year(), t.Month(), t.Day(), t.Hour())
}

// GenerateHourDimensionWithOffset generates hour dimension string (YYYYMMDDHH) for a given timestamp with a day offset
// dayOffset can be negative to go back in time (e.g., -30 for 30 days before)
func GenerateHourDimensionWithOffset(timestamp int64, dayOffset int) string {
	t := time.Unix(timestamp, 0).UTC()
	// Add the day offset
	t = t.AddDate(0, 0, dayOffset)
	return fmt.Sprintf("%04d%02d%02d%02d", t.Year(), t.Month(), t.Day(), t.Hour())
}
