package main

import (
	"errors"
	"regexp"
	"time"

	log "github.com/sirupsen/logrus"
)

func SnapshotName(schedule string, now time.Time) string {
	log.WithFields(log.Fields{"schedule": schedule, "now": now}).Debugf("starting")
	log.WithFields(log.Fields{"schedule": schedule, "now": now}).Debugf("done")

	return schedule + "-" + now.Format(zfsSnapshotDatePattern) + "--" + cfg.ScheduleDuration[schedule]
}

func (s *ZfsSnapshot) Valid() bool {
	log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("starting")
	defer log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("done")

	re := regexp.MustCompile(zfsSnapshotPattern)
	return re.MatchString(s.name)
}

func (s *ZfsSnapshot) Schedule() (string, error) {
	log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("starting")
	defer log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("done")

	if !s.Valid() {
		err := errors.New("invalid name")
		log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name, "call": "Valid", "error": err}).Errorf("")
		return "", err
	}

	re := regexp.MustCompile(zfsSnapshotPattern)

	return re.ReplaceAllString(s.name, "${Schedule}"), nil

}

func (s *ZfsSnapshot) Expiration() (time.Time, error) {
	log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("starting")
	defer log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("done")

	if !s.Valid() {
		err := errors.New("invalid name")
		log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name, "call": "Valid", "error": err}).Errorf("")
		return time.Now(), err
	}

	re := regexp.MustCompile(zfsSnapshotPattern)

	expirationString := re.ReplaceAllString(s.name, "${Expiration}")

	timestampTime, err := s.Timestamp()
	if err != nil {
		log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name, "call": "Timestamp", "error": err}).Errorf("")
		return time.Now(), err
	}

	return Expiration(timestampTime, expirationString)

}

func (s *ZfsSnapshot) Timestamp() (time.Time, error) {
	log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("starting")
	defer log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("done")

	t := time.Now()

	if !s.Valid() {
		err := errors.New("invalid name")
		log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name, "call": "Valid", "error": err}).Errorf("")
		return t, err
	}

	re := regexp.MustCompile(zfsSnapshotPattern)

	timestampString := re.ReplaceAllString(s.name, "${Timestamp}")
	timestampTime, err := time.ParseInLocation(zfsSnapshotDatePattern, timestampString, cfg.timezone)
	if err != nil {
		log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name, "call": "time.Parse", "attr": timestampString, "error": err}).Errorf("")
		return t, err
	}

	return timestampTime, nil
}

func (s *ZfsSnapshot) Expired(now time.Time) (bool, error) {
	log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("starting")
	defer log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("done")

	if !s.Valid() {
		err := errors.New("invalid name")
		log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name, "call": "Valid", "error": err}).Errorf("")
		return false, err
	}

	expirationTime, err := s.Expiration()
	if err != nil {
		log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name, "call": "Timestamp", "error": err}).Errorf("")
		return false, err
	}

	if now.After(expirationTime) {
		return true, nil
	} else {
		return false, nil
	}

}

func (s *ZfsSnapshot) String() string {
	return s.fs.path + "@" + s.name
}

func (s *ZfsSnapshot) Delete() error {
	log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("starting")
	defer log.WithFields(log.Fields{"box": s.fs.zfs.box.name, "fs": s.fs.path, "name": s.name}).Debugf("done")

	return s.fs.DelSnapshot(s.name)
}
