/*
 * Copyright (C) 2019 Philipp Haefelfinger (http://www.haefelfinger.ch/). All Rights Reserved.
 * This application is licensed under GPLv2. See the LICENSE file in the root directory of the project.
 */

package app

import (
	"errors"
	"flag"
	"github.com/sirupsen/logrus"
	"os"
	"path"
	"path/filepath"
	"strings"
)

var (
	imagesRootPath = flag.String("imagesRootPath", "", "This is the images root path that should be mirrored to piwigo.")
	dryRun         = flag.Bool("dryRun", true, "If set to true, all actions are run except the real filesystem modifications")
)

func Run() {
	imagesRootFolder := *imagesRootPath
	if imagesRootFolder == "" {
		logErrorAndExit(errors.New("No images root folder set, exiting."), 1)
	}

	err, jpgFiles := findAllJpgFiles(imagesRootFolder)
	if err != nil {
		logrus.Errorf("Could not clean up %s", imagesRootFolder)
		logErrorAndExit(err, 2)
	}

	filesWithMissingSidecar := getJpesWithoutRawSideCar(jpgFiles)
	logrus.Infof("Found %d of %d images to delete in %s", len(filesWithMissingSidecar), len(jpgFiles), imagesRootFolder)

	if len(jpgFiles) == len(filesWithMissingSidecar) {
		logrus.Warnf("Did not find any sidecar files in %s. Are you sure this is the right path to look for jpgs without raw sidecars? Cancelling executing!", imagesRootFolder)
		logErrorAndExit(errors.New("Total files of jpegs and missing sidecars are the same, cancelling!"), 3)
	}

	if !(*dryRun) {
		deleteFiles(filesWithMissingSidecar)
	} else {
		logrus.Warnln("Skipping delete of images as flag dryRun is set to true!")
	}

}

func deleteFiles(filesWithMissingSidecar []string) {
	for _, fileToDelete := range filesWithMissingSidecar {
		logrus.Infof("Deleting %s", fileToDelete)
		err := os.Remove(fileToDelete)
		if err != nil {
			logrus.Errorf("Could not delete %s because of %v", fileToDelete, err)
		}
	}
}

func logErrorAndExit(err error, exitCode int) {
	logrus.Errorln(err)
	os.Exit(exitCode)
}

func getJpesWithoutRawSideCar(jpgFiles []string) []string {
	var filesWithMissingSidecar []string
	for _, jpgFile := range jpgFiles {
		dir, fileName := filepath.Split(jpgFile)

		newFileName := filenameWithoutExtension(fileName) + ".cr2"
		newFilePath := filepath.Join(dir, newFileName)

		if exists, err := fileExists(newFilePath); exists {
			logrus.Debugf("Found exising sidecar, keeping jpeg %s", jpgFile)

		} else if err == nil && !exists {
			logrus.Infof("Found jpeg with missing raw file, schedule for delete %s", jpgFile)
			filesWithMissingSidecar = append(filesWithMissingSidecar, jpgFile)
		} else {
			logrus.Errorf("There was an error on checking %s: %v", jpgFile, err)
		}
	}
	return filesWithMissingSidecar
}

func findAllJpgFiles(basePath string) (error, []string) {
	var files []string

	err := filepath.Walk(basePath, func(path string, info os.FileInfo, err error) error {
		if strings.HasPrefix(info.Name(), ".") {
			logrus.Debugf("Skipping hidden file or directory %s", path)
			return nil
		}

		extension := strings.ToLower(filepath.Ext(path))
		if (extension != ".jpg" && extension != ".jpeg") || info.IsDir() {
			return nil
		}

		logrus.Debugf("Found file %s", path)
		files = append(files, path)

		return nil
	})
	return err, files
}

func filenameWithoutExtension(fn string) string {
	return strings.TrimSuffix(fn, path.Ext(fn))
}

func fileExists(filePath string) (bool, error) {
	_, err := os.Stat(filePath)
	if err == nil {
		logrus.Debugf("file %s exists", filePath)
		return true, nil
	} else if os.IsNotExist(err) {
		logrus.Debugf("file %s does not exist", filePath)
		return false, nil
	} else {
		logrus.Debugf("file %s stat error: %v", filePath, err)
		return false, err
	}
}
