package server

import (
	"be-vpn/internal/dto"
	"be-vpn/internal/model"
	"be-vpn/internal/storage"
	"github.com/gin-gonic/gin"
	"log"
	"math/rand"
	"net/http"
	"strconv"
	"sync"
	"time"
)

var nodes = make([]*model.Node, 0)
var locker = sync.RWMutex{}
var totalFreeDuration = uint64((time.Hour * 1).Milliseconds() / 1000)

func Config(c *gin.Context) {
	deviceId := c.Query("deviceId")
	usedDuration, err := storage.GetUsedDuration(deviceId)
	if err != nil {
		dto.Error(c, err)
		return
	}
	c.JSON(http.StatusOK, dto.ConfigResponse{
		Response: dto.NewOkResponse(),
		Data: dto.ConfigResult{
			FreeTrialDuration: totalFreeDuration - usedDuration,
			Timestamp:         time.Now().Unix(),
			Node:              convert2DtoNode(healthNodes()[0]),
		},
	})
}

func AddUsedDuration(c *gin.Context) {
	deviceId := c.Query("deviceId")
	usedDurationStr := c.Query("usedDuration")
	log.Printf("deviceId: %s, usedDuration: %s", deviceId, usedDurationStr)

	usedDuration, err := strconv.ParseUint(usedDurationStr, 10, 64)
	if err != nil {
		dto.Error(c, err)
		return
	}
	if existed, err := storage.AddUsedDuration(deviceId, usedDuration); err != nil {
		dto.Error(c, err)
		return
	} else {
		freeTrialDuration := totalFreeDuration - existed
		if freeTrialDuration > totalFreeDuration || freeTrialDuration < 0 {
			freeTrialDuration = 0
		}
		c.JSON(http.StatusOK, dto.ConfigResponse{
			Response: dto.NewOkResponse(),
			Data: dto.ConfigResult{
				FreeTrialDuration: freeTrialDuration,
				Timestamp:         time.Now().Unix(),
				Node:              convert2DtoNode(healthNodes()[0]),
			},
		})
	}
}

func Register(c *gin.Context) {
	locker.Lock()
	defer locker.Unlock()

	var request dto.RegisterRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		dto.BadRequest(c, err)
		return
	}

	for _, node := range nodes {
		if node.Ip == request.Ip {
			node.Ip = request.Ip
			node.Secret = request.Secret
			node.CountryCode = request.CountryCode
			node.CountryName = request.CountryName
			node.LastUpdateTime = time.Now()
			c.JSON(http.StatusOK, dto.RegisterResponse{
				Response: dto.NewOkResponse(),
				Data: dto.RegisterResult{
					Success: true,
				},
			})
			return
		}
	}
	node := &model.Node{
		Ip:             request.Ip,
		Secret:         request.Secret,
		LastUpdateTime: time.Now(),
	}
	nodes = append(nodes, node)
	log.Printf("update nodes: %+v", nodes)
}

func List(c *gin.Context) {
	locker.RLock()
	defer locker.RUnlock()

	dtoNodes := make([]dto.Node, 0)
	for _, node := range healthNodes() {
		dtoNodes = append(dtoNodes, convert2DtoNode(node))
	}

	c.JSON(http.StatusOK, dto.ListResponse{
		Response: dto.NewOkResponse(),
		Data:     dtoNodes,
	})
}

func SecretRandom(c *gin.Context) {
	locker.RLock()
	defer locker.RUnlock()

	random := rand.Intn(len(nodes))

	for i, node := range nodes {
		if i == random {
			c.Header("Content-Disposition", "attachment; filename=client.ovpn")
			c.Data(http.StatusOK, "plain/text", []byte(node.Secret))
			return
		}
	}
	c.JSON(http.StatusNotFound, gin.H{
		"message": "not found",
	})
}

func Secret(c *gin.Context) {
	locker.RLock()
	defer locker.RUnlock()

	var request dto.DetailRequest
	if err := c.ShouldBindQuery(&request); err != nil {
		dto.BadRequest(c, err)
		return
	}

	for _, node := range nodes {
		if node.Ip == request.Ip {
			//secret, err := util.AesEncrypt([]byte(node.Secret))
			//if err != nil {
			//	dto.Error(c, err)
			//	return
			//}
			c.Header("Content-Disposition", "attachment; filename=client.ovpn")
			c.Data(http.StatusOK, "plain/text", []byte(node.Secret))
			return
		}
	}
	c.JSON(http.StatusNotFound, gin.H{
		"message": "not found ip",
	})
}

func Health(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"status": "up"})
}

func healthNodes() []*model.Node {
	healthNodes := make([]*model.Node, 0)
	for _, node := range nodes {
		if node.LastUpdateTime.Add(10 * time.Second).After(time.Now()) {
			healthNodes = append(healthNodes, node)
		}
	}
	return healthNodes
}

func convert2DtoNode(node *model.Node) dto.Node {
	icon := ""
	if node.CountryCode == "BR" {
		icon = "http://v.starttransfernow.com/static/BR.jpg"
	} else if node.CountryCode == "DE" {
		icon = "http://v.starttransfernow.com/static/DE.jpg"
	} else if node.CountryCode == "HK" {
		icon = "http://v.starttransfernow.com/static/HK.jpg"
	} else if node.CountryCode == "JA" {
		icon = "http://v.starttransfernow.com/static/JA.jpg"
	} else if node.CountryCode == "US" {
		icon = "http://v.starttransfernow.com/static/US.jpg"
	}
	return dto.Node{
		Ip:          node.Ip,
		CountryCode: node.CountryCode,
		CountryName: node.CountryName,
		Icon:        icon,
		//Icon:        "https://img.zcool.cn/community/010a5a57dbc2140000018c1b0a9b5f.png",
	}
}
