package caddyhugo

import (
	"fmt"
	"html/template"
	"net/http"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"

	"git.stephensearles.com/stephen/acedoc"

	"github.com/gohugoio/hugo/deps"
	"github.com/gohugoio/hugo/hugolib"
	"github.com/mholt/caddy"
	"github.com/mholt/caddy/caddyhttp/httpserver"
	"github.com/spf13/afero"
)

func init() {
	plugin := CaddyHugo{}

	// register a "generic" plugin, like a directive or middleware
	caddy.RegisterPlugin("hugo", caddy.Plugin{
		ServerType: "http",
		Action:     plugin.SetupCaddy,
	})

	// ... there are others. See the godoc.
}

// CaddyHugo implements the plugin
type CaddyHugo struct {
	ServerType string
	Site       *httpserver.SiteConfig
	HugoSites  *hugolib.HugoSites
	HugoCfg    *deps.DepsCfg

	Dir string

	Media *MediaSource

	docs map[string]*editSession
	mtx  sync.Mutex

	authorTmpl, adminTmpl, editTmpl *template.Template

	ltime uint64
}

// Build rebuilds the cached state of the site. TODO: determine if this republishes
func (ch *CaddyHugo) Build() error {
	err := ch.HugoSites.Build(hugolib.BuildCfg{ResetState: true})
	if err != nil {
		return fmt.Errorf("error building hugo sites: %v", err)
	}

	return nil
}

// BasePath returns the directory that the CaddyHugo internal/author pages are under
func (ch *CaddyHugo) BasePath() string {
	return "/hugo"
}

func docname(orig string) string {
	orig = strings.Replace(orig, " ", "-", -1)
	return strings.ToLower(orig)
}

func (ch *CaddyHugo) docFilename(orig string) string {
	return filepath.Join(ch.Dir, docname(orig))
}

// Publish really renders new content into the public directory
func (ch *CaddyHugo) Publish() error {
	err := ch.persistAllEdits()
	if err != nil {
		return err
	}
	cmd := exec.Command("hugo")
	cmd.Dir = ch.Dir
	_, err = cmd.CombinedOutput()
	if err != nil {
		return err
	}

	return nil
}

// TmplData collects data for template execution
func (ch *CaddyHugo) TmplData(r *http.Request, docref *editSession) interface{} {
	var doc *acedoc.Document
	if docref != nil {
		doc = docref.doc
	}
	if ch.HugoSites != nil && ch.HugoSites.Fs != nil {
		ch.HugoSites.Cfg.Set("buildDrafts", true)
		ch.HugoSites.Fs.Destination = afero.NewMemMapFs()
		ch.Build()
	}
	return &tmplData{ch.Site, r, ch, doc, docref}
}
