// Package main implements the fetch_ml configuration linter
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/jfraeys/fetch_ml/internal/fileutil"
	"github.com/xeipuuv/gojsonschema"
	"gopkg.in/yaml.v3"
)

func main() {
	var (
		schemaPath string
		failFast   bool
	)

	flag.StringVar(&schemaPath, "schema", "configs/schema.yaml", "Path to JSON schema in YAML format")
	flag.BoolVar(&failFast, "fail-fast", false, "Stop on first error")
	flag.Parse()

	if flag.NArg() == 0 {
		log.Fatalf("usage: configlint [--schema path] [--fail-fast] <config files...>")
	}

	schemaLoader, err := loadSchema(schemaPath)
	if err != nil {
		log.Fatalf("failed to load schema: %v", err)
	}

	var hadError bool
	for _, configPath := range flag.Args() {
		if err := validateConfig(schemaLoader, configPath); err != nil {
			hadError = true
			fmt.Fprintf(os.Stderr, "configlint: %s: %v\n", configPath, err)
			if failFast {
				os.Exit(1)
			}
		}
	}

	if hadError {
		os.Exit(1)
	}

	fmt.Println("All configuration files are valid.")
}

func loadSchema(schemaPath string) (gojsonschema.JSONLoader, error) {
	data, err := fileutil.SecureFileRead(schemaPath)
	if err != nil {
		return nil, err
	}

	var schemaYAML any
	if err := yaml.Unmarshal(data, &schemaYAML); err != nil {
		return nil, err
	}

	schemaJSON, err := json.Marshal(schemaYAML)
	if err != nil {
		return nil, err
	}

	return gojsonschema.NewBytesLoader(schemaJSON), nil
}

func validateConfig(schemaLoader gojsonschema.JSONLoader, configPath string) error {
	data, err := fileutil.SecureFileRead(configPath)
	if err != nil {
		return err
	}

	ext := strings.ToLower(filepath.Ext(configPath))
	var decoded any
	switch ext {
	case ".toml":
		var configTOML map[string]any
		if _, err := toml.Decode(string(data), &configTOML); err != nil {
			return fmt.Errorf("failed to parse TOML: %w", err)
		}
		decoded = configTOML
	default:
		// YAML (default)
		var configYAML any
		dec := yaml.NewDecoder(bytes.NewReader(data))
		dec.KnownFields(false)
		if err := dec.Decode(&configYAML); err != nil {
			return fmt.Errorf("failed to parse YAML: %w", err)
		}
		decoded = configYAML
	}

	configJSON, err := json.Marshal(decoded)
	if err != nil {
		return err
	}

	result, err := gojsonschema.Validate(schemaLoader, gojsonschema.NewBytesLoader(configJSON))
	if err != nil {
		return err
	}

	if result.Valid() {
		fmt.Printf("%s: valid\n", configPath)
		return nil
	}

	var builder strings.Builder
	for _, issue := range result.Errors() {
		builder.WriteString("- ")
		builder.WriteString(issue.String())
		builder.WriteByte('\n')
	}

	return fmt.Errorf("validation failed:\n%s", builder.String())
}
