package diagnostic

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
)

const (
	linuxManagedLogsPath          = "/var/log/cloudflared.err"
	darwinManagedLogsPath         = "/Library/Logs/com.cloudflare.cloudflared.err.log"
	linuxServiceConfigurationPath = "/etc/systemd/system/cloudflared.service"
)

type HostLogCollector struct {
	client HTTPClient
}

func NewHostLogCollector(client HTTPClient) *HostLogCollector {
	return &HostLogCollector{
		client,
	}
}

func extractLogsFromJournalCtl(ctx context.Context) (*LogInformation, error) {
	// nolint: gosec
	outputHandle, err := os.Create(filepath.Join(os.TempDir(), logFilename))
	if err != nil {
		return nil, fmt.Errorf("error opening output file: %w", err)
	}

	defer func() { _ = outputHandle.Close() }()

	command := exec.CommandContext(
		ctx,
		"journalctl",
		"--since",
		"2 weeks ago",
		"-u",
		"cloudflared.service",
	)

	return PipeCommandOutputToFile(command, outputHandle)
}

func getServiceLogPath() (string, error) {
	switch runtime.GOOS {
	case "darwin":
		{
			path := darwinManagedLogsPath
			if _, err := os.Stat(path); err == nil {
				return path, nil
			}

			userHomeDir, err := os.UserHomeDir()
			if err != nil {
				return "", fmt.Errorf("error getting user home: %w", err)
			}

			return filepath.Join(userHomeDir, darwinManagedLogsPath), nil
		}
	case "linux":
		{
			return linuxManagedLogsPath, nil
		}
	default:
		return "", ErrManagedLogNotFound
	}
}

func (collector *HostLogCollector) Collect(ctx context.Context) (*LogInformation, error) {
	logConfiguration, err := collector.client.GetLogConfiguration(ctx)
	if err != nil {
		return nil, fmt.Errorf("error getting log configuration: %w", err)
	}

	if logConfiguration.uid == 0 {
		_, statSystemdErr := os.Stat(linuxServiceConfigurationPath)

		_, statServiceConfigurationErr := os.Stat(linuxServiceConfigurationPath)
		if statSystemdErr == nil && statServiceConfigurationErr == nil && runtime.GOOS == "linux" {
			return extractLogsFromJournalCtl(ctx)
		}

		path, err := getServiceLogPath()
		if err != nil {
			return nil, err
		}

		return NewLogInformation(path, false, false), nil
	}

	if logConfiguration.logFile != "" {
		return NewLogInformation(logConfiguration.logFile, false, false), nil
	} else if logConfiguration.logDirectory != "" {
		return NewLogInformation(logConfiguration.logDirectory, false, true), nil
	}

	return nil, ErrLogConfigurationIsInvalid
}
