// Package parser provides functions for parsing Markdown templates into
// structured JSON objects that conform to a JSON Schema.
package parser

import (
	"fmt"

	"git.max-richter.dev/max/marka/parser/decoders"
	"git.max-richter.dev/max/marka/parser/matcher"
	"git.max-richter.dev/max/marka/registry"
	"git.max-richter.dev/max/marka/template"
)

func DetectType(markdownContent string) (string, error) {
	defaultSchemaContent, err := registry.GetTemplate("_default")
	if err != nil {
		return "", fmt.Errorf("could not get schema -> %w", err)
	}

	defaultSchema, err := template.CompileTemplate(defaultSchemaContent)
	if err != nil {
		return "", fmt.Errorf("failed to compile template -> %w", err)
	}

	blocks := matcher.MatchBlocksFuzzy(markdownContent, defaultSchema, 0.3)

	result, err := decoders.Parse(blocks)
	if err != nil {
		return "", fmt.Errorf("failed to parse blocks -> %w", err)
	}

	if result, ok := result.(map[string]any); ok {
		if contentType, ok := result["_type"]; ok {
			return contentType.(string), nil
		}
		return "", fmt.Errorf("frontmatter did not contain '_type'")
	}

	return "", fmt.Errorf("could not parse frontmatter")
}

func MatchBlocks(markdownContent, templateContent string) ([]matcher.Block, error) {
	tpl, err := template.CompileTemplate(templateContent)
	if err != nil {
		return nil, fmt.Errorf("failed to compile template -> %w", err)
	}

	return matcher.MatchBlocksFuzzy(markdownContent, tpl, 0.3), nil
}

func ParseFile(markdownContent string) (any, error) {
	contentType, err := DetectType(markdownContent)
	if err != nil {
		return nil, fmt.Errorf("could not detect type -> %w", err)
	}

	templateContent, err := registry.GetTemplate(contentType)
	if err != nil {
		return nil, fmt.Errorf("could not get template -> %w", err)
	}

	return ParseFileWithTemplate(markdownContent, templateContent)
}

func ParseFileWithTemplate(markdownContent string, templateContent string) (any, error) {
	tpl, err := template.CompileTemplate(templateContent)
	if err != nil {
		return nil, fmt.Errorf("failed to compile template -> %w", err)
	}

	blocks := matcher.MatchBlocksFuzzy(markdownContent, tpl, 0.3)

	result, err := decoders.Parse(blocks)
	if err != nil {
		return nil, fmt.Errorf("failed to compile blocks -> %w", err)
	}

	return result, nil
}
