package dunst

import (
	"Sithego/themer"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"text/template"
)

type Adapter struct {
	OutputDir string
}

type Option func(*Adapter)

func WithOutputDir(dir string) Option {
	return func(a *Adapter) {
		a.OutputDir = dir
	}
}

func New(opt ...Option) *Adapter {
	home, _ := os.UserHomeDir()
	a := &Adapter{
		OutputDir: filepath.Join(home, ".config", "dunst"),
	}
	for _, o := range opt {
		o(a)
	}
	return a
}

func (a *Adapter) Name() string { return "Dunst" }

type tmplData struct {
	Theme   themer.Theme
	Padding struct {
		V int
		H int
	}
	Radius struct {
		Small int
		Base  int
		Large int
	}
}

func (a *Adapter) Generate(t themer.Theme) error {
	templatePath := filepath.Join("themer", "adapters", "dunst", "dunstrc")
	templ, err := template.ParseFiles(templatePath)
	if err != nil {
		return err
	}

	if err := os.MkdirAll(a.OutputDir, 0o755); err != nil {
		return err
	}
	outputPath := filepath.Join(a.OutputDir, "dunstrc")
	f, err := os.Create(outputPath)
	if err != nil {
		return err
	}
	defer f.Close()

	data := tmplData{Theme: t}

	vp, hp := parsePaddingPair(t.Spacing.Padding)
	data.Padding.V = vp
	data.Padding.H = hp
	data.Radius.Small = parsePx(t.Spacing.RadiusSmall)
	if data.Radius.Small == 0 {
		data.Radius.Small = 4
	}
	data.Radius.Base = parsePx(t.Spacing.Radius)
	if data.Radius.Base == 0 {
		data.Radius.Base = data.Radius.Small
	}
	data.Radius.Large = parsePx(t.Spacing.RadiusLarge)
	if data.Radius.Large == 0 {
		data.Radius.Base = data.Radius.Large
	}

	if err := templ.Execute(f, data); err != nil {
		return err
	}
	return nil
}

var rePxPair = regexp.MustCompile(`(?i)\b(\d+)\s*px\b(?:\s+(\d+)\s*px\b)?`)
var rePx = regexp.MustCompile(`(?i)\b(\d+)\s*px\b`)

func parsePaddingPair(s string) (int, int) {
	s = strings.TrimSpace(s)
	if s == "" {
		return 0, 0
	}
	m := rePxPair.FindStringSubmatch(s)
	if len(m) == 3 {
		v, _ := strconv.Atoi(m[1])
		if m[2] != "" {
			h, _ := strconv.Atoi(m[2])
			return v, h
		}
		// single value provided -> use for both
		return v, v
	}
	// fallback: try generic px
	m2 := rePx.FindStringSubmatch(s)
	if len(m2) == 2 {
		v, _ := strconv.Atoi(m2[1])
		return v, v
	}
	return 0, 0
}

func parsePx(s string) int {
	s = strings.TrimSpace(s)
	m := rePx.FindStringSubmatch(s)
	if len(m) == 2 {
		v, _ := strconv.Atoi(m[1])
		return v
	}
	return 0
}
