package handlers

import (
	"database/sql"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
	"lan-manager/server/db"
	"lan-manager/server/middleware"
	"lan-manager/server/models"
	"lan-manager/server/services"
)

type PVEHandler struct {
	service *services.PVEHostService
}

func NewPVEHandler() *PVEHandler {
	return &PVEHandler{
		service: services.NewPVEHostService(),
	}
}

// List 获取 PVE 主机列表
func (h *PVEHandler) List(c *gin.Context) {
	if !middleware.IsAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
		return
	}

	hosts, err := h.service.GetAll()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// 密码不返回给前端
	for i := range hosts {
		hosts[i].PasswordEnc = ""
	}

	c.JSON(http.StatusOK, hosts)
}

// Get 获取单个 PVE 主机
func (h *PVEHandler) Get(c *gin.Context) {
	if !middleware.IsAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
		return
	}

	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
		return
	}

	host, err := h.service.GetByID(id)
	if err != nil {
		if err == sql.ErrNoRows {
			c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	host.PasswordEnc = ""
	host.Password = ""
	c.JSON(http.StatusOK, host)
}

// Create 创建 PVE 主机
func (h *PVEHandler) Create(c *gin.Context) {
	if !middleware.IsAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
		return
	}

	var host models.PVEHost
	if err := c.ShouldBindJSON(&host); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
		return
	}

	if host.Name == "" || host.Hostname == "" || host.Username == "" || host.Password == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "missing required fields"})
		return
	}

	if host.Port == 0 {
		host.Port = 8006
	}

	if err := h.service.Create(&host); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	idPtr := host.ID
	middleware.LogOperation("create", "pve_host", &idPtr, host.Name, "", host.Hostname+":"+strconv.Itoa(host.Port), c.ClientIP(), middleware.CurrentUser(c))

	host.PasswordEnc = ""
	host.Password = ""
	c.JSON(http.StatusCreated, host)
}

// Update 更新 PVE 主机
func (h *PVEHandler) Update(c *gin.Context) {
	if !middleware.IsAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
		return
	}

	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
		return
	}

	var host models.PVEHost
	if err := c.ShouldBindJSON(&host); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
		return
	}

	host.ID = id

	// 如果密码为空，说明不更新密码
	if host.Password == "" {
		existing, err := h.service.GetByID(id)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
		host.PasswordEnc = existing.PasswordEnc
	}

	if err := h.service.Update(&host); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	middleware.LogOperation("update", "pve_host", &id, host.Name, "", host.Hostname+":"+strconv.Itoa(host.Port), c.ClientIP(), middleware.CurrentUser(c))

	host.PasswordEnc = ""
	c.JSON(http.StatusOK, host)
}

// Delete 删除 PVE 主机
func (h *PVEHandler) Delete(c *gin.Context) {
	if !middleware.IsAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
		return
	}

	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
		return
	}

	// 获取主机名用于日志
	host, _ := h.service.GetByID(id)
	hostName := ""
	if host != nil {
		hostName = host.Name
	}

	if err := h.service.Delete(id); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	middleware.LogOperation("delete", "pve_host", &id, hostName, "", "", c.ClientIP(), middleware.CurrentUser(c))

	c.JSON(http.StatusOK, gin.H{"message": "deleted"})
}

// HostStatus 检测 PVE 节点连接状态
func (h *PVEHandler) HostStatus(c *gin.Context) {
	if !middleware.IsAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
		return
	}

	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
		return
	}

	status, err := h.service.GetHostStatus(id)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"status": "offline", "error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"status": status})
}

// HostVMList 获取 PVE 节点上的虚拟机列表
func (h *PVEHandler) HostVMList(c *gin.Context) {
	if !middleware.IsAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
		return
	}

	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
		return
	}

	vms, err := h.service.GetHostVMList(id)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, vms)
}

// VMStatus 获取虚拟机状态
func (h *PVEHandler) VMStatus(c *gin.Context) {
	if !middleware.IsAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
		return
	}

	machineID, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
		return
	}

	var pveHostID *int64
	var pveVMID sql.NullString
	err = db.DB.QueryRow(`SELECT pve_host_id, pve_vmid FROM machines WHERE id = ?`, machineID).Scan(&pveHostID, &pveVMID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "machine not found"})
		return
	}

	if pveHostID == nil || !pveVMID.Valid || pveVMID.String == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "machine not linked to PVE VM"})
		return
	}

	status, err := h.service.GetVMStatus(*pveHostID, pveVMID.String)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, status)
}

// VMStart 启动虚拟机
func (h *PVEHandler) VMStart(c *gin.Context) {
	if !middleware.IsAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
		return
	}

	machineID, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
		return
	}

	var pveHostID *int64
	var pveVMID sql.NullString
	err = db.DB.QueryRow(`SELECT pve_host_id, pve_vmid FROM machines WHERE id = ?`, machineID).Scan(&pveHostID, &pveVMID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "machine not found"})
		return
	}

	if pveHostID == nil || !pveVMID.Valid || pveVMID.String == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "machine not linked to PVE VM"})
		return
	}

	if err := h.service.StartVM(*pveHostID, pveVMID.String); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// 记录操作日志
	machineName := ""
	db.DB.QueryRow("SELECT hostname FROM machines WHERE id = ?", machineID).Scan(&machineName)
	idPtr := machineID
	middleware.LogOperation("start", "vm", &idPtr, machineName, "", "vmid:"+pveVMID.String, c.ClientIP(), middleware.CurrentUser(c))

	c.JSON(http.StatusOK, gin.H{"message": "started"})
}

// VMStop 停止虚拟机
func (h *PVEHandler) VMStop(c *gin.Context) {
	if !middleware.IsAdmin(c) {
		c.JSON(http.StatusForbidden, gin.H{"error": "admin only"})
		return
	}

	machineID, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
		return
	}

	var pveHostID *int64
	var pveVMID sql.NullString
	err = db.DB.QueryRow(`SELECT pve_host_id, pve_vmid FROM machines WHERE id = ?`, machineID).Scan(&pveHostID, &pveVMID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "machine not found"})
		return
	}

	if pveHostID == nil || !pveVMID.Valid || pveVMID.String == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "machine not linked to PVE VM"})
		return
	}

	if err := h.service.StopVM(*pveHostID, pveVMID.String); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// 记录操作日志
	machineName := ""
	db.DB.QueryRow("SELECT hostname FROM machines WHERE id = ?", machineID).Scan(&machineName)
	idPtr := machineID
	middleware.LogOperation("stop", "vm", &idPtr, machineName, "", "vmid:"+pveVMID.String, c.ClientIP(), middleware.CurrentUser(c))

	c.JSON(http.StatusOK, gin.H{"message": "stopped"})
}

