package main

import (
	"io"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
)

var logFileWriter io.WriteCloser = &nopWriteCloser{}

// nopWriteCloser is a struct that implements io.WriteCloser interface.
type nopWriteCloser struct {
}

// Write method for nopWriteCloser.
func (d *nopWriteCloser) Write(p []byte) (n int, err error) {
	// Simply return the length of p and no error, simulating a successful write.
	return len(p), nil
}

// Close method for nopWriteCloser.
func (d *nopWriteCloser) Close() error {
	// Return nil to simulate a successful close.
	return nil
}

// Route all logging
func systemRouteAllLogging(logfile string) {
	logFileHandle, err := os.OpenFile(logfile, os.O_WRONLY, 0666)
	if err != nil {
		return
	}

	logFileWriter = logFileHandle

	// Redirect stdout and stderr to logFileWriter
	os.Stdout = logFileHandle
	os.Stderr = logFileHandle

	// Redirect log facility to /dev/null
	log.SetOutput(logFileHandle)
}

func systemCloseLogging() {
	logFileWriter.Close()
}

func systemGetAppDataPath() string {
	return filepath.Join(os.Getenv("USERPROFILE"), "AppData")
}

// systemCheckDirExists checks if the directory at the given path exists.
func systemIsDirExisting(path string) bool {
	// Get file info
	info, err := os.Stat(path)
	if err != nil {
		// If the error is due to the file not existing, return false
		if os.IsNotExist(err) {
			return false
		}
		// For any other errors, you may want to handle them as needed
		return false
	}

	// Check if the info corresponds to a directory
	return info.IsDir()
}

func systemGetFilesInDirectory(path string) ([]string, bool) {
	var filesInDirectory []string

	files, err := os.ReadDir(path)
	if err != nil {
		return nil, false
	}

	for _, file := range files {
		filesInDirectory = append(filesInDirectory, file.Name())
	}

	return filesInDirectory, true
}

func systemIsFileExisting(path string) bool {
	// Get file info
	info, err := os.Stat(path)
	if err != nil {
		// If the error is due to the file not existing, return false
		if os.IsNotExist(err) {
			return false
		}
		// For any other errors, you may want to handle them as needed
		return false
	}

	// Check if the info corresponds to a regular file
	return !info.IsDir()
}

func systemGetSysWOW64Files() []string {
	sysWOW64Path := filepath.Join("C:", "Windows", "SysWOW64")
	files, _ := systemGetFilesInDirectory(sysWOW64Path)
	return files
}

func systemGetSystem32Files() []string {
	system32Path := filepath.Join("C:", "Windows", "system32")
	files, _ := systemGetFilesInDirectory(system32Path)
	return files
}

func systemGetWellKnownWINEOSFiles() []string {
	var wineFiles []string
	var foundFiles []string

	foundFiles = append(foundFiles, systemGetSysWOW64Files()...)
	foundFiles = append(foundFiles, systemGetSystem32Files()...)

	for _, file := range foundFiles {
		if strings.Contains(file, "wine") && strings.Contains(file, ".exe") {
			wineFiles = append(wineFiles, file)
		}
	}

	return wineFiles
}

func systemGetWellKnownExistingPaths() []string {
	var existingPaths []string

	appDataPath := systemGetAppDataPath()
	if ok := systemIsDirExisting(appDataPath); !ok {
		log.Println("\t❌", appDataPath)
	}

	wellKnownPathsToCheck := []string{
		filepath.Join(appDataPath, "Local", "Programs", "Python"),           // TODO search python installations
		filepath.Join(appDataPath, "Roaming", "npm", "node_modules", "bin"), // TODO search python installations
	}

	homeDirectory, err := os.UserHomeDir()
	if err == nil {
		homeDirPathsToCheck := []string{
			filepath.Join(homeDirectory, "go", "bin"),
		}
		wellKnownPathsToCheck = append(wellKnownPathsToCheck, homeDirPathsToCheck...)
	}

	for _, path := range wellKnownPathsToCheck {
		if ok := systemIsDirExisting(path); ok {
			existingPaths = append(existingPaths, path)
			log.Println("\t✅", path)
		} else {
			log.Println("\t❌", path)
		}
	}

	return existingPaths
}

func systemIgnoreAllSignals() {
	// Create a channel to receive OS signals.
	sigs := make(chan os.Signal, 1)

	// Notify the signal channel for all signals (you can add more if needed)
	signal.Notify(sigs)

	// This goroutine receives signals but does nothing with them.
	go func() {
		for sig := range sigs {
			// Signal received but ignored
			_ = sig
			log.Println("Received OS signal", sig)
		}
	}()
}
