package jenkins

import (
	"embed"
	"fmt"
	"html/template"
	"io"
	"os"

	"freeleaps.com/gitops/initializer/api/v1alpha1"
)

//go:embed templates/*
var embeddedTemplates embed.FS

type JenkinsfileGenerator struct {
	io.Closer
	Instance   *v1alpha1.ProjectInitialize
	workingDir string
	generated  bool
}

const leftDelim = "[["
const rightDelim = "]]"

func (jg *JenkinsfileGenerator) prepareWorkingDir() error {
	path, err := os.MkdirTemp("", fmt.Sprintf("jenkinsfile-gen-%s-*", jg.Instance.Name))
	if err != nil {
		return fmt.Errorf("failed to create jenkinsfile generator temp dir: %w", err)
	}
	jg.workingDir = path
	return nil
}

func (jg *JenkinsfileGenerator) readTemplate(name string) (*template.Template, error) {
	tpl := template.New(name)
	templateBytes, err := embeddedTemplates.ReadFile(name)
	if err != nil {
		return nil, fmt.Errorf("failed to read template %s: %w", name, err)
	}
	tpl, err = tpl.
		Delims(leftDelim, rightDelim).
		Parse(string(templateBytes))
	if err != nil {
		return nil, fmt.Errorf("failed to parse template %s: %w", name, err)
	}
	return tpl, nil
}

func (jg *JenkinsfileGenerator) Generate() error {
	if jg.Instance == nil {
		return fmt.Errorf("instance is nil")
	}

	if err := jg.prepareWorkingDir(); err != nil {
		return err
	}

	tpl, err := jg.readTemplate("templates/Jenkinsfile.tpl")
	if err != nil {
		return err
	}

	jenkinsfileFd, err := os.Create(jg.workingDir + "/Jenkinsfile")
	if err != nil {
		return fmt.Errorf("failed to create Jenkinsfile: %w", err)
	}
	defer jenkinsfileFd.Close()

	if err := tpl.Execute(jenkinsfileFd, jg.Instance.Spec); err != nil {
		return fmt.Errorf("failed to render Jenkinsfile with template: %w", err)
	}
	jg.generated = true

	return nil
}

func (jg *JenkinsfileGenerator) Close() error {
	if jg.workingDir != "" {
		return os.RemoveAll(jg.workingDir)
	}
	return nil
}

func (jg *JenkinsfileGenerator) ReadGeneratedJenkinsfile() ([]byte, error) {
	if !jg.generated {
		return nil, fmt.Errorf("jenkinsfile not generated")
	}

	jenkinsfileBytes, err := os.ReadFile(jg.workingDir + "/Jenkinsfile")
	if err != nil {
		return nil, fmt.Errorf("failed to read generated Jenkinsfile: %w", err)
	}

	return jenkinsfileBytes, nil
}
