package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"lunar/engine/streams/validation"
	"lunar/engine/utils"
	"net/http"
	"os"
	"path/filepath"
)

func main() {
	http.HandleFunc(ValidationEndpointPath, validateFlowsHandler)

	port := GetValidatorPort()
	fmt.Printf("Flows Validator Server is running on port %v\n", port)
	if err := http.ListenAndServe(":"+port, nil); err != nil {
		fmt.Printf("Error starting server: %v\n", err)
	}
}

func validateFlowsHandler(writer http.ResponseWriter, req *http.Request) {
	if req.Method != http.MethodPost {
		http.Error(writer, "Invalid method, only POST is allowed", http.StatusMethodNotAllowed)
		return
	}

	var input ValidationInput
	if err := json.NewDecoder(req.Body).Decode(&input); err != nil {
		http.Error(writer, fmt.Sprintf("Invalid JSON input: %v", err), http.StatusBadRequest)
		return
	}

	var result ValidationResult
	if !input.IsFolderSpecified() {
		// Clear existing setup, if any
		if err := os.RemoveAll(input.GetRoot()); err != nil && !os.IsNotExist(err) {
			http.Error(writer,
				fmt.Sprintf("Failed to clear existing setup: %v", err), http.StatusInternalServerError)
			return
		}

		// Write Base64 files to folder
		if err := os.Mkdir(input.GetRoot(), 0o755); err != nil && !os.IsExist(err) {
			http.Error(writer,
				fmt.Sprintf("Failed to create folder: %v", err), http.StatusInternalServerError)
			return
		}

		if err := ensureFoldersExist(input); err != nil {
			http.Error(writer,
				fmt.Sprintf("Failed to create folders: %v", err), http.StatusInternalServerError)
			return
		}

		if err := writeSetupFilesToDir(input); err != nil {
			http.Error(writer, fmt.Sprintf("Failed to write files: %v", err), http.StatusInternalServerError)
			return
		}
	}

	result = validateFlowsSetup(input)
	writer.Header().Set("Content-Type", "application/json")
	_ = json.NewEncoder(writer).Encode(result)

	// remove setup
	if !input.IsFolderSpecified() {
		_ = os.RemoveAll(input.GetRoot())
	}
}

func validateFlowsSetup(input ValidationInput) ValidationResult {
	validation := validation.NewValidator().WithValidationDir(input.GetRoot())
	if err := validation.Validate(); err != nil {
		err = utils.LastErrorWithUnwrappedDepth(err, 1)
		return ValidationResult{
			Success: false,
			Message: fmt.Sprintf("Validation failed: %v", err.Error()),
		}
	}

	return ValidationResult{
		Success: true,
		Message: "Validation completed successfully",
	}
}

func ensureFoldersExist(input ValidationInput) error {
	paths := []string{
		input.GetFlowsPath(),
		input.GetQuotasPath(),
		input.GetPathParamsPath(),
	}

	for _, path := range paths {
		if err := os.MkdirAll(path, 0o755); err != nil && !os.IsExist(err) {
			return fmt.Errorf("failed to create directory %s: %v", path, err)
		}
	}
	return nil
}

func writeSetupFilesToDir(input ValidationInput) error {
	if input.GatewayConfig != "" {
		if err := writeBase64File(input.GatewayConfig, input.GetGatewayConfigPath()); err != nil {
			return err
		}
	}

	for i, flow := range input.Flows {
		file := fmt.Sprintf("flow_%d.yaml", i+1)
		if err := writeBase64File(flow, filepath.Join(input.GetFlowsPath(), file)); err != nil {
			return err
		}
	}

	for i, pathParam := range input.PathParams {
		file := fmt.Sprintf("path_param_%d.yaml", i+1)
		if err := writeBase64File(pathParam, filepath.Join(input.GetPathParamsPath(), file)); err != nil {
			return err
		}
	}

	for i, quota := range input.Quotas {
		file := fmt.Sprintf("quota_%d.yaml", i+1)
		if err := writeBase64File(quota, filepath.Join(input.GetQuotasPath(), file)); err != nil {
			return err
		}
	}

	return nil
}

func writeBase64File(encodedData, filePath string) error {
	data, err := base64.StdEncoding.DecodeString(encodedData)
	if err != nil {
		return fmt.Errorf("failed to decode Base64 data: %v", err)
	}

	if err := os.WriteFile(filePath, data, 0o644); err != nil {
		return fmt.Errorf("failed to write file: %v", err)
	}

	return nil
}
