package server

import (
	"encoding/json"
	"io"
	"net/http"
	"os"
	"path"
	"strconv"
	"time"

	"repositories.action2quare.com/ayo/go-ayo/logger"
	"repositories.action2quare.com/ayo/houston/shared"
)

func (h *houstonHandler) GetAgents(w http.ResponseWriter, r *http.Request) {
	enc := json.NewEncoder(w)
	enc.Encode(h.Operation().Hosts())
}

func (h *houstonHandler) GetDeploySources(w http.ResponseWriter, r *http.Request) {
	files, err := os.ReadDir("deploys")
	if err != nil {
		logger.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	getVersions := func(name string) []string {
		var out []string
		files, _ := os.ReadDir(path.Join("deploys", name))
		for _, fd := range files {
			if fd.IsDir() {
				out = append(out, fd.Name())
			}
		}
		return out
	}

	out := make(map[string][]string)
	for _, fd := range files {
		if fd.IsDir() {
			out[fd.Name()] = getVersions(fd.Name())
		}
	}

	enc := json.NewEncoder(w)
	enc.Encode(out)
}

func (h *houstonHandler) UploadDeploySource(w http.ResponseWriter, r *http.Request) {
	// 	<form action="/houston" method="post" enctype="multipart/form-data">
	//     <input type="file" name="file">
	//     <input type="text" name="name">
	//     <input type="text" name="version">
	//     <input type="submit" value="업로드">
	//   </form>
	file, header, err := r.FormFile("file")
	if err != nil {
		logger.Error(err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	defer file.Close()

	contents, err := io.ReadAll(file)
	if err != nil {
		logger.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	version := r.FormValue("version")
	name := r.FormValue("name")
	ext := path.Ext(header.Filename)

	// deploys 폴더는 파일시스템 서비스이므로 다운로드 가능
	filename := path.Join("deploys", name, version, name+ext)
	if err = os.MkdirAll(path.Dir(filename), os.ModePerm); err != nil {
		logger.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	// 파일 저장
	err = os.WriteFile(filename, contents, 0644)
	if err != nil {
		logger.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
}

func (h *houstonHandler) Deploy(w http.ResponseWriter, r *http.Request) {
	// 	<form action="/houston" method="post" enctype="multipart/form-data">
	//     <input type="text" name="name">
	//     <input type="text" name="version">
	//     <input type="text" name="targets">
	//     <input type="submit" value="업로드">
	//   </form>
	name := r.FormValue("name")
	version := r.FormValue("version")
	traws := r.FormValue("targets")

	var targets []string
	if len(traws) > 0 {
		if err := json.Unmarshal([]byte(traws), &targets); err != nil {
			logger.Error(err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}
	}

	if len(name) == 0 || len(version) == 0 || len(targets) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	relPath := path.Join("deploys", name, version)
	files, err := os.ReadDir(relPath)
	if err != nil {
		logger.Error(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	latestTime := time.Time{}
	var latestFilename string
	for _, fd := range files {
		if fd.IsDir() {
			continue
		}

		fi, _ := fd.Info()
		if fi.ModTime().After(latestTime) {
			latestFilename = fi.Name()
			latestTime = fi.ModTime()
		}
	}
	if len(latestFilename) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	h.Operation().Deploy(MakeDeployRequest(
		shared.DeployRequest{
			Name:    name,
			Version: version,
			Url:     path.Join(relPath, latestFilename),
		},
		targets,
	))
}

func (h *houstonHandler) StartProcess(w http.ResponseWriter, r *http.Request) {
	// 	<form action="/houston" method="post" enctype="multipart/form-data">
	//     <input type="text" name="name">
	//     <input type="text" name="version">
	// 		<input type="text" name="args">
	//     <input type="text" name="targets">
	//     <input type="submit" value="업로드">
	//   </form>
	name := r.FormValue("name")
	version := r.FormValue("version")
	args := r.FormValue("args")
	traws := r.FormValue("targets")

	var targets []string
	if len(traws) > 0 {
		if err := json.Unmarshal([]byte(traws), &targets); err != nil {
			logger.Error(err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}
	}

	if len(name) == 0 || len(version) == 0 || len(targets) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	h.Operation().StartProcess(MakeStartProcessRequest(shared.StartProcessRequest{
		Name:    name,
		Version: version,
		Args:    args, // 실행 파일 포함 e.g. "biglocal.exe -port=8090 -dev",
	}, targets))
}

func (h *houstonHandler) StopProcess(w http.ResponseWriter, r *http.Request) {
	// 	<form action="/houston" method="post" enctype="multipart/form-data">
	//     <input type="text" name="name">
	//     <input type="text" name="version">
	// 		<input type="text" name="args">
	//     <input type="text" name="targets">
	//     <input type="submit" value="업로드">
	//   </form>
	name := r.FormValue("name")
	if len(name) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	version := r.FormValue("version") // option
	pidstr := r.FormValue("pid")      // option
	traws := r.FormValue("targets")

	var targets []string
	if len(traws) > 0 {
		if err := json.Unmarshal([]byte(traws), &targets); err != nil {
			logger.Error(err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}
	}

	pid, _ := strconv.Atoi(pidstr)

	h.Operation().StopProcess(MakeStopProcessRequest(shared.StopProcessRequest{
		Name:    name,
		Version: version,
		Pid:     int32(pid),
	}, targets))
}

func (h *houstonHandler) UploadLogs(w http.ResponseWriter, r *http.Request) {
	// 	<form action="/houston" method="post" enctype="multipart/form-data">
	//     <input type="text" name="name">
	//     <input type="text" name="version">
	//		<input type="text" name="filter">
	//     <input type="text" name="targets">
	//     <input type="submit" value="업로드">
	//   </form>
	name := r.FormValue("name")
	if len(name) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	version := r.FormValue("version") // option
	traws := r.FormValue("targets")
	filter := r.FormValue("filter")

	if len(filter) == 0 {
		filter = "logs/*"
	}
	var targets []string
	if err := json.Unmarshal([]byte(traws), &targets); err != nil {
		logger.Error(err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	h.Operation().Upload(MakeUploadRequest(shared.UploadRequest{
		Name:    name,
		Version: version,
		Url:     "upload",
		Filter:  filter,
	}, targets))
}

func (h *houstonHandler) GetLogFileLinks(w http.ResponseWriter, r *http.Request) {
	// 	<form action="/houston" method="post" enctype="multipart/form-data">
	//     <input type="text" name="name">
	//     <input type="text" name="version">
	//   </form>
	name := r.FormValue("name")
	version := r.FormValue("version")
	if len(name) == 0 || len(version) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	if version == "latest" {
		version, _ = shared.FindLastestVersion(path.Join("downloads", name))
	}

	root := path.Join("downloads", name, version)
	logfiles, err := os.ReadDir(root)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	var out []string
	for _, lf := range logfiles {
		out = append(out, path.Join(root, lf.Name()))
	}

	enc := json.NewEncoder(w)
	enc.Encode(out)
}
