package translate

import (
	"fmt"
	"github.com/charmbracelet/log"
	"gitlab.schukai.com/oss/bob/types"
	"gopkg.in/yaml.v3"
	"os"
	"strings"
)

func Do(dataFile, api string, targetLanguages []string) {

	data, err := os.ReadFile(dataFile)
	if err != nil {
		log.Fatalf("Error reading data file %s: %v", dataFile, err)
	}

	storage := types.NewPageDataStorage()
	err = yaml.Unmarshal(data, storage)
	if err != nil {
		log.Fatalf("Error unmarshalling data file %s: %v", dataFile, err)
	}

	// 2. Alle zu übersetzenden Zeichenketten sammeln (nur unique)
	uniqueTexts := collectUniqueTexts(&storage)
	fmt.Printf("Found %d unique texts to translate.\n", len(uniqueTexts))

	// 3. Für die definierten Zielsprachen (de, it, pl, fr) die Übersetzung per DEEPL API holen
	translationsByLang := make(map[string]map[string]string)

	for _, lang := range targetLanguages {
		log.Info("Translating to %s...\n", lang)

		var trans map[string]string
		var err error

		switch api {
		case "aws":
			trans, err = translateTextsAws(uniqueTexts, lang)
		case "deepl":
			trans, err = translateTextsDeepl(uniqueTexts, lang)
		case "openai":
			trans, err = translateTextsOpenAI(uniqueTexts, lang)
		}

		if err != nil {
			log.Fatalf("Error translating to %s: %v", lang, err)
			return
		}

		translationsByLang[lang] = trans
	}

	// 4. Für jede Sprache: Original-Struktur kopieren, übersetzte Texte an derselben Stelle eintragen und als YAML speichern.
	for _, lang := range targetLanguages {

		for _, page := range storage {

			translatedPage := applyTranslations(*page, translationsByLang[lang])
			// Optional: Sprache im PageData anpassen
			translatedPage.Lang = lang

			outData, err := yaml.Marshal(&translatedPage)
			if err != nil {
				log.Fatalf("Error marshalling translated data for %s: %v", lang, err)
			}

			filename := fmt.Sprintf("%s.yaml", lang)
			err = os.WriteFile(filename, outData, 0644)
			if err != nil {
				log.Fatalf("Error writing translated data for %s: %v", lang, err)
			}
			log.Info("Translated data for %s written to %s.\n", lang, filename)
		}
	}
}

// collectUniqueTexts sammelt alle eindeutigen Zeichenketten aus den Feldern, die übersetzt werden sollen.
func collectUniqueTexts(storage *types.PageDataStorage) []string {
	unique := make(map[string]struct{})
	add := func(s string) {
		s = strings.TrimSpace(s)
		if s != "" {
			unique[s] = struct{}{}
		}
	}

	for _, page := range *storage {

		// PageData.Title
		add(page.Title)

		// PageData.Meta (nur Werte)
		for _, v := range page.Meta {
			add(v)
		}

		// Text.Text
		for _, t := range page.Text {
			add(t.Text)
		}

		// Image: Alt und Title
		for _, img := range page.Images {
			add(img.Alt)
			add(img.Title)
		}

		// Anchor: Title
		for _, anc := range page.Anchors {
			add(anc.Title)
		}

		// Translations: Werte in KeyValues (falls String)
		for _, trans := range page.Translations {
			for _, v := range trans.KeyValues {
				if s, ok := v.(string); ok {
					add(s)
				}
			}
		}

	}

	// In Slice umwandeln
	texts := make([]string, 0, len(unique))
	for s := range unique {
		texts = append(texts, s)
	}
	return texts
}

// applyTranslations nimmt die Originalstruktur und ersetzt alle übersetzbaren Felder durch die entsprechenden Übersetzungen.
func applyTranslations(page types.PageData, translations map[string]string) types.PageData {
	newPage := page

	// PageData.Title
	if t, ok := translations[page.Title]; ok {
		newPage.Title = t
	}

	// PageData.Meta
	newMeta := make(map[string]string)
	for k, v := range page.Meta {
		if t, ok := translations[v]; ok {
			newMeta[k] = t
		} else {
			newMeta[k] = v
		}
	}
	newPage.Meta = newMeta

	// Text.Text
	for i, t := range newPage.Text {
		if tr, ok := translations[t.Text]; ok {
			newPage.Text[i].Text = tr
		}
	}

	// Images: Alt und Title
	for i, img := range newPage.Images {
		if tr, ok := translations[img.Alt]; ok {
			newPage.Images[i].Alt = tr
		}
		if tr, ok := translations[img.Title]; ok {
			newPage.Images[i].Title = tr
		}
	}

	// Anchors: Title
	for i, anc := range newPage.Anchors {
		if tr, ok := translations[anc.Title]; ok {
			newPage.Anchors[i].Title = tr
		}
	}

	// Translations: KeyValues (nur falls Value ein String ist)
	for i, t := range newPage.Translations {
		newKV := make(map[string]interface{})
		for k, v := range t.KeyValues {
			if s, ok := v.(string); ok {
				if tr, found := translations[s]; found {
					newKV[k] = tr
				} else {
					newKV[k] = s
				}
			} else {
				newKV[k] = v
			}
		}
		newPage.Translations[i].KeyValues = newKV
	}

	return newPage
}