package handlers

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"alpine-router/mihomo"
)

func HandleMihomoStatus(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		fail(w, http.StatusMethodNotAllowed, "method not allowed")
		return
	}
	ok(w, mihomo.Status())
}

func HandleMihomoStart(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		fail(w, http.StatusMethodNotAllowed, "method not allowed")
		return
	}
	if err := mihomo.Start(); err != nil {
		fail(w, http.StatusInternalServerError, err.Error())
		return
	}
	ok(w, map[string]string{"message": "mihomo started"})
}

func HandleMihomoStop(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		fail(w, http.StatusMethodNotAllowed, "method not allowed")
		return
	}
	if err := mihomo.Stop(); err != nil {
		fail(w, http.StatusInternalServerError, err.Error())
		return
	}
	ok(w, map[string]string{"message": "mihomo stopped"})
}

func HandleMihomoRestart(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		fail(w, http.StatusMethodNotAllowed, "method not allowed")
		return
	}
	if err := mihomo.Restart(); err != nil {
		fail(w, http.StatusInternalServerError, err.Error())
		return
	}
	ok(w, map[string]string{"message": "mihomo restarted"})
}

func HandleMihomoConfig(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		cfg, err := mihomo.LoadConfig()
		if err != nil {
			fail(w, http.StatusInternalServerError, err.Error())
			return
		}
		ok(w, cfg)

	case http.MethodPut:
		var cfg map[string]interface{}
		if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
			fail(w, http.StatusBadRequest, "invalid json: "+err.Error())
			return
		}
		if err := mihomo.SaveConfig(cfg); err != nil {
			fail(w, http.StatusInternalServerError, "save config: "+err.Error())
			return
		}
		ok(w, map[string]string{"message": "config saved"})

	default:
		fail(w, http.StatusMethodNotAllowed, "method not allowed")
	}
}

func HandleMihomoLogs(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		fail(w, http.StatusMethodNotAllowed, "method not allowed")
		return
	}
	ok(w, mihomo.Logs())
}

func HandleMihomoConfigYAML(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		data, err := os.ReadFile(mihomo.ConfigPath())
		if err != nil {
			if os.IsNotExist(err) {
				w.WriteHeader(http.StatusNotFound)
				return
			}
			fail(w, http.StatusInternalServerError, err.Error())
			return
		}
		w.Header().Set("Content-Type", "text/yaml; charset=utf-8")
		w.Write(data)

	case http.MethodPut:
		data, err := io.ReadAll(r.Body)
		if err != nil {
			fail(w, http.StatusBadRequest, "read body: "+err.Error())
			return
		}
		if err := os.MkdirAll(mihomo.DataDir(), 0755); err != nil {
			fail(w, http.StatusInternalServerError, "mkdir: "+err.Error())
			return
		}
		tmp := mihomo.ConfigPath() + ".tmp"
		if err := os.WriteFile(tmp, data, 0644); err != nil {
			fail(w, http.StatusInternalServerError, "write: "+err.Error())
			return
		}
		if err := os.Rename(tmp, mihomo.ConfigPath()); err != nil {
			fail(w, http.StatusInternalServerError, "rename: "+err.Error())
			return
		}
		ok(w, map[string]string{"message": "config.yaml updated"})

	default:
		fail(w, http.StatusMethodNotAllowed, "method not allowed")
	}
}

func HandleMihomoUploadCore(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		fail(w, http.StatusMethodNotAllowed, "method not allowed")
		return
	}

	if err := r.ParseMultipartForm(64 << 20); err != nil {
		fail(w, http.StatusBadRequest, "parse form: "+err.Error())
		return
	}

	file, header, err := r.FormFile("core")
	if err != nil {
		fail(w, http.StatusBadRequest, "file required: "+err.Error())
		return
	}
	defer file.Close()

	name := header.Filename
	for _, arch := range []string{"amd64", "arm64", "armv7"} {
		if strings.Contains(name, arch) {
			dstPath := filepath.Join(mihomo.CoresDir(), fmt.Sprintf("mihomo-linux-%s", arch))
			if err := os.MkdirAll(mihomo.CoresDir(), 0755); err != nil {
				fail(w, http.StatusInternalServerError, "mkdir: "+err.Error())
				return
			}
			dst, err := os.Create(dstPath)
			if err != nil {
				fail(w, http.StatusInternalServerError, "create: "+err.Error())
				return
			}
			defer dst.Close()
			if _, err := io.Copy(dst, file); err != nil {
				fail(w, http.StatusInternalServerError, "write: "+err.Error())
				return
			}
			if err := os.Chmod(dstPath, 0755); err != nil {
				fail(w, http.StatusInternalServerError, "chmod: "+err.Error())
				return
			}
			ok(w, map[string]string{"message": "core uploaded", "arch": arch})
			return
		}
	}

	dstPath := filepath.Join(mihomo.CoresDir(), "mihomo-linux-amd64")
	if err := os.MkdirAll(mihomo.CoresDir(), 0755); err != nil {
		fail(w, http.StatusInternalServerError, "mkdir: "+err.Error())
		return
	}
	dst, err := os.Create(dstPath)
	if err != nil {
		fail(w, http.StatusInternalServerError, "create: "+err.Error())
		return
	}
	defer dst.Close()
	if _, err := io.Copy(dst, file); err != nil {
		fail(w, http.StatusInternalServerError, "write: "+err.Error())
		return
	}
	if err := os.Chmod(dstPath, 0755); err != nil {
		fail(w, http.StatusInternalServerError, "chmod: "+err.Error())
		return
	}
	ok(w, map[string]string{"message": "core uploaded", "path": dstPath})
}