package nginx

import (
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/uozi-tech/cosy/logger"
)

// Regular expressions for parsing directives from nginx -T output
const (
	// AccessLogRegexPattern matches access_log directive with unquoted path
	// Matches: access_log /path/to/file
	AccessLogRegexPattern = `(?m)^\s*access_log\s+([^\s;]+)`

	// ErrorLogRegexPattern matches error_log directive with unquoted path
	// Matches: error_log /path/to/file
	ErrorLogRegexPattern = `(?m)^\s*error_log\s+([^\s;]+)`

	// PIDRegexPattern matches pid directive with unquoted path
	// Matches: pid /path/to/file;
	PIDRegexPattern = `(?m)^\s*pid\s+([^\s;]+)`
)

var (
	accessLogRegex *regexp.Regexp
	errorLogRegex  *regexp.Regexp
	pidRegex       *regexp.Regexp
)

func init() {
	accessLogRegex = regexp.MustCompile(AccessLogRegexPattern)
	errorLogRegex = regexp.MustCompile(ErrorLogRegexPattern)
	pidRegex = regexp.MustCompile(PIDRegexPattern)
}

// isValidRegularFile checks if the given path is a valid regular file
// Returns true if the path exists and is a regular file (not a directory or special file)
func isValidRegularFile(path string) bool {
	if path == "" {
		return false
	}

	fileInfo, err := os.Stat(path)
	if err != nil {
		logger.Debug("nginx.isValidRegularFile: failed to stat file", "path", path, "error", err)
		return false
	}

	// Check if it's a regular file (not a directory or special file)
	if !fileInfo.Mode().IsRegular() {
		logger.Debug("nginx.isValidRegularFile: path is not a regular file", "path", path, "mode", fileInfo.Mode())
		return false
	}

	return true
}

// isCommentedLine checks if a line is commented (starts with #)
func isCommentedLine(line string) bool {
	trimmed := strings.TrimSpace(line)
	return strings.HasPrefix(trimmed, "#")
}

// getAccessLogPathFromNginxT extracts the first access_log path from nginx -T output
func getAccessLogPathFromNginxT() string {
	output := getNginxT()
	if output == "" {
		logger.Error("nginx.getAccessLogPathFromNginxT: nginx -T output is empty")
		return ""
	}

	lines := strings.Split(output, "\n")

	for _, line := range lines {
		// Skip commented lines
		if isCommentedLine(line) {
			continue
		}

		matches := accessLogRegex.FindStringSubmatch(line)
		if len(matches) >= 2 {
			logPath := matches[1]

			// Skip 'off' directive
			if logPath == "off" {
				continue
			}
			// Handle relative paths
			if !filepath.IsAbs(logPath) {
				logPath = filepath.Join(GetPrefix(), logPath)
			}
			resolvedPath := resolvePath(logPath)

			// Validate that the path is a regular file
			if !isValidRegularFile(resolvedPath) {
				logger.Warn("nginx.getAccessLogPathFromNginxT: path is not a valid regular file", "path", resolvedPath)
				continue
			}

			return resolvedPath
		}
	}

	logger.Error("nginx.getAccessLogPathFromNginxT: no valid access_log file found")
	return ""
}

// getErrorLogPathFromNginxT extracts the first error_log path from nginx -T output
func getErrorLogPathFromNginxT() string {
	output := getNginxT()
	if output == "" {
		logger.Error("nginx.getErrorLogPathFromNginxT: nginx -T output is empty")
		return ""
	}

	lines := strings.Split(output, "\n")

	for _, line := range lines {
		// Skip commented lines
		if isCommentedLine(line) {
			continue
		}

		matches := errorLogRegex.FindStringSubmatch(line)
		if len(matches) >= 2 {
			logPath := matches[1]

			// Handle relative paths
			if !filepath.IsAbs(logPath) {
				logPath = filepath.Join(GetPrefix(), logPath)
			}
			resolvedPath := resolvePath(logPath)

			// Validate that the path is a regular file
			if !isValidRegularFile(resolvedPath) {
				logger.Warn("nginx.getErrorLogPathFromNginxT: path is not a valid regular file", "path", resolvedPath)
				continue
			}

			return resolvedPath
		}
	}

	logger.Error("nginx.getErrorLogPathFromNginxT: no valid error_log file found")
	return ""
}

// getPIDPathFromNginxT extracts the pid file path from nginx -T output.
// This is needed because nginx -V returns the compile-time default --pid-path,
// but Docker images like nginx-unprivileged override this at runtime via the
// "pid" directive in nginx.conf (e.g., pid /tmp/nginx.pid;).
func getPIDPathFromNginxT() string {
	output := getNginxT()
	if output == "" {
		logger.Error("nginx.getPIDPathFromNginxT: nginx -T output is empty")
		return ""
	}

	lines := strings.Split(output, "\n")

	for _, line := range lines {
		// Skip commented lines
		if isCommentedLine(line) {
			continue
		}

		matches := pidRegex.FindStringSubmatch(line)
		if len(matches) >= 2 {
			pidPath := matches[1]

			// Handle relative paths
			if !filepath.IsAbs(pidPath) {
				pidPath = filepath.Join(GetPrefix(), pidPath)
			}

			return resolvePath(pidPath)
		}
	}

	logger.Debug("nginx.getPIDPathFromNginxT: no pid directive found in nginx -T output")
	return ""
}
