package main

import (
	_ "embed"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"
)

//go:embed web/overlay.html
var overlayHTML string

//go:embed web/themes/aurora.html
var themeAurora string

//go:embed web/themes/starfield.html
var themeStarfield string

//go:embed web/themes/gradient.html
var themeGradient string

//go:embed web/themes/particles.html
var themeParticles string

//go:embed web/themes/fractal.html
var themeFractal string

//go:embed web/themes/text.html
var themeText string

//go:embed web/themes/audio-viz.html
var themeAudioViz string

var themeMap = map[ThemeName]string{
	ThemeAurora:   themeAurora,
	ThemeStar:     themeStarfield,
	ThemeGradient: themeGradient,
	ThemeParticle: themeParticles,
	ThemeFractal:  themeFractal,
	ThemeText:     themeText,
	ThemeAudioViz: themeAudioViz,
}

func buildWallpaperHTML(cfg *Config) string {
	var bg string

	if cfg.WallpaperType == WPTheme {
		if t, ok := themeMap[cfg.Theme]; ok {
			bg = t
		} else {
			bg = themeAurora
		}
	} else {
		bg = buildBgHTML(cfg)
	}

	if bg == "" {
		bg = themeAurora
	}
	bgWrapped := fmt.Sprintf(`<div id="bg-layer">%s</div>`, bg)
	if cfg.HideWallpaper {
		bgWrapped = `<div id="bg-layer" style="display:none"></div>`
	}

	initialData := map[string]interface{}{
		"backgroundHtml":   bgWrapped,
		"layout":           string(cfg.Layout),
		"showSeconds":      cfg.ShowSeconds,
		"userZodiac":       cfg.Zodiac,
		"wallpaperVisible": !cfg.HideWallpaper,
		"photoFrameMode":   cfg.PhotoFrameMode && cfg.PhotoDir != "",
		"cardVisibility": map[string]bool{
			"time":      !cfg.HideTime,
			"weather":   !cfg.HideWeather,
			"zodiac":    !cfg.HideZodiac,
			"knowledge": !cfg.HideKnowledge,
			"ainews":    !cfg.HideAINews,
			"photo":     !cfg.HidePhoto,
		},
	}
	dataJSON, _ := json.Marshal(initialData)
	inject := fmt.Sprintf(`<script>window.__INITIAL_DATA__=%s;</script>`, string(dataJSON))

	// 注入自定义文字
	if cfg.WallpaperType == WPTheme && cfg.Theme == ThemeText && cfg.WallpaperText != "" {
		escaped, _ := json.Marshal(cfg.WallpaperText)
		inject += fmt.Sprintf(`<script>window.wallpaperText=%s;</script>`, string(escaped))
	}

	// 注入音频可视化配置
	if cfg.WallpaperType == WPTheme && cfg.Theme == ThemeAudioViz {
		inject += fmt.Sprintf(
			`<script>window.__audioVizStyle=%q;window.__audioVizSensitivity=%f;window.__audioVizColors=%q;</script>`,
			cfg.AudioVizStyle, cfg.AudioSensitivity, cfg.AudioColorScheme,
		)
	}

	return strings.Replace(overlayHTML, "</head>", inject+"</head>", 1)
}

func imageToDataURI(path string) string {
	data, err := os.ReadFile(path)
	if err != nil {
		log.Println("读取图片失败:", err)
		return ""
	}
	ext := strings.ToLower(filepath.Ext(path))
	mime := "image/jpeg"
	switch ext {
	case ".png":
		mime = "image/png"
	case ".gif":
		mime = "image/gif"
	case ".webp":
		mime = "image/webp"
	case ".bmp":
		mime = "image/bmp"
	}
	return fmt.Sprintf("data:%s;base64,%s", mime, base64.StdEncoding.EncodeToString(data))
}

func reloadWallpaper() {
	if wv == nil || wvHwnd == 0 {
		return
	}
	cfg := loadConfig()

	// 音频捕获生命周期
	if cfg.WallpaperType == WPTheme && cfg.Theme == ThemeAudioViz {
		if !audioActiveState() {
			startAudioCapture()
		}
	} else {
		if audioActiveState() {
			stopAudioCapture()
		}
	}

	// 非主题壁纸切换：仅替换 #bg-layer，不销毁卡片状态
	if cfg.WallpaperType != WPTheme {
		updateBackground(cfg)
		return
	}

	// 主题切换需要 SetHtml（canvas+script），之后恢复卡片数据
	html := buildWallpaperHTML(cfg)
	select {
	case htmlQueue <- html:
	default:
	}
	procPostMessageW.Call(wvHwnd, wmSetHtml, 0, 0)
	go reloadAllCards()
}

func buildBgHTML(cfg *Config) string {
	switch cfg.WallpaperType {
	case WPImage:
		if cfg.ImagePath != "" {
			src := imageToDataURI(cfg.ImagePath)
			if src != "" {
				return buildCoverImgHTML(src)
			}
		}
	case WPBing:
		if p := getCurrentBingPath(); p != "" {
			if _, err := os.Stat(p); err == nil {
				src := imageToDataURI(p)
				if src != "" {
					return buildCoverImgHTML(src)
				}
			}
		}
	case WPColor:
		if cfg.ColorGradient && cfg.Color2 != "" {
			return fmt.Sprintf(`<div style="position:fixed;top:0;left:0;width:100%%;height:100%%;z-index:1;background:linear-gradient(135deg,%s,%s);"></div>`, cfg.Color1, cfg.Color2)
		}
		return fmt.Sprintf(`<div style="position:fixed;top:0;left:0;width:100%%;height:100%%;z-index:1;background:%s;"></div>`, cfg.Color1)
	}
	return ""
}

const coverImgTpl = `<img src="%s" style="position:fixed;top:0;left:0;width:100%%;height:100%%;object-fit:cover;z-index:1;">`

func buildCoverImgHTML(src string) string {
	return fmt.Sprintf(coverImgTpl, src)
}

func updateBackground(cfg *Config) {
	bg := buildBgHTML(cfg)
	if bg == "" {
		return
	}
	display := ""
	if cfg.HideWallpaper {
		display = ` style="display:none"`
	}
	html := fmt.Sprintf(`<div id="bg-layer"%s>%s</div>`, display, bg)
	// Update Vue reactive state via bridge
	evalJS(fmt.Sprintf(`if(window.__updateBackgroundHtml) window.__updateBackgroundHtml(%q);`, html))
	// Fallback: direct DOM update for non-Vue contexts
	evalJS(fmt.Sprintf(`var el=document.getElementById('bg-layer'); if(el && !window.__updateBackgroundHtml){el.outerHTML=%q;}`, html))
}

func reloadAllCards() {
	time.Sleep(800 * time.Millisecond)

	evalJS(fmt.Sprintf(`window.userZodiac = %q;`, loadConfig().Zodiac))

	if cached := loadHoroscopeCache(); cached != nil {
		pushHoroscopeInfo(cached)
	}
	if cached := loadAINewsCache(); cached != nil {
		pushAINews(cached)
	}
	cfg := loadConfig()
	if cfg.KnowledgeKeyword != "" && !cfg.HideKnowledge {
		if cached := getRandomKnowledgeCard(cfg.KnowledgeKeyword); cached != "" {
			pushKnowledgeJSON(cached, cfg.KnowledgeKeyword)
		}
	}
	if city := getCurrentCity(); city.ID != "" {
		go fetchAndPushWeather(city)
	}
	if cfg.PhotoDir != "" && !cfg.HidePhoto {
		go func() {
			time.Sleep(500 * time.Millisecond)
			pushCurrentPhoto(cfg.PhotoInterval)
		}()
	}
}

func bingReloadImage() {
	if wv == nil || wvHwnd == 0 {
		return
	}
	p := getCurrentBingPath()
	if p == "" {
		return
	}
	src := imageToDataURI(p)
	if src == "" {
		return
	}
	evalJS(fmt.Sprintf(`var bg=document.querySelector('#bg-layer img'); if(bg) bg.src=%q;`, src))
}
