package controller

import (
	"net"
	"net/http"
	"backend/app/response"
	"backend/model"

	//"error"
	"time"

	"github.com/labstack/echo/v4"

	//"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"os"
	//"github.com/google/uuid"
	//"github.com/go-playground/validator"
	//"github.com/sirupsen/logrus"
)

type File struct {
	FileName   string `json:"fileName"`
	FileType   string `json:"fileType"`
	Expiration int    `json:"expiration"`
	User       string `json:"user"`
	Passwd     string `json:"passwd"`
	SessionId  string `json:"sessionId"`
	FileLink   string `json:"fileLink"`
	//Expiry     time.Time `json:"expiry"` // 有效期
	//Content string `json:"content"`
}

type pass struct {
	SessionId string `json:"sessionId"`
	Passwd    string `json:"passwd"`
	FileLink  string `json:"fileLink"`
}

type Text struct {
	text string `json:"text"`
}

func Ping(c echo.Context) error {
	// just a demo
	return response.SendResponse(c, http.StatusOK, "", "pong!")
}

// 通过用户名密码来设置cookie
func AskPasswd(c echo.Context) error {
	//
	info := new(pass)
	if err := c.Bind(info); err != nil {
		return err
	}
	if info.Passwd == "" || info.SessionId == "" {
		//return c.String(http.StatusBadRequest, "请输入用户名和密码")
		c.String(http.StatusBadRequest, "请输入SessionId和密码")
		return echo.ErrBadRequest
	}

	if model.Createlink(info.SessionId, info.Passwd, info.FileLink) == true {
		// 成功建立连接
		SetCookie(c, info)
		return c.String(http.StatusOK, "登录成功")
	}
	return c.String(http.StatusOK, "登录失败") //
}

// 设置cookie name sid, value link
func SetCookie(c echo.Context, info *pass) error {
	cookie := new(http.Cookie)
	cookie.Name =  "User"// 标识为user
	//cookie.Value = string(uuid)  // 通过uuid和数据库，确定user是谁
	cookie.Value = info.SessionId
	cookie.Path = "/"
	// cookie有效期为3600秒
	cookie.MaxAge = 3600

	// 在数据库中加入 cookie记录

	// 设置cookie
	c.SetCookie(cookie)
	return c.String(http.StatusOK, "cookie设置")
}

// 接收浏览器发来的文件，把文件储存在.\files\目录下
// 成功则返回上传成功，否则报错
func RecvFile(c echo.Context) error {
	file, err := c.FormFile("file")
	if err != nil {
		return err
	}
	// 打开用户上传的文件
	src, err := file.Open()
	if err != nil {
		return err
	}
	defer src.Close()

	info := new(File)
	if err = c.Bind(info); err != nil {
		return err
	}
	// 创建目标文件，就是我们打算把用户上传的文件保存到什么地方
	// file.Filename 参数指的是我们以用户上传的文件名，作为目标文件名，也就是服务端保存的文件名跟用户上传的文件名一样
	if info.FileType == "" {
		info.FileType = "txt"
	}
	filePath := "./files/" + info.FileType + "/" + file.Filename
	dst, err := os.Create(filePath)
	if err != nil {
		// 是否目录不完整引起的问题
		if os.IsExist(err) == false {
			if catalogBuild(info.FileType) != nil {
				return err
			}
			dst, err = os.Create(filePath)
			if err != nil {
				return err
			}
		}
	}
	// 获取文件大小
	fi, _ := dst.Stat()
	if fi.Size() > 8*1024*10224 {
		c.HTML(http.StatusOK, fmt.Sprintf("<p>文件上传失败: 文件大小超过8MB</p>"))
	}
	if err != nil {
		fmt.Println(err)
		return err
	}
	defer dst.Close()

	// 这里将用户上传的文件复制到服务端的目标文件
	if _, err = io.Copy(dst, src); err != nil {
		return err
	}

	// 更新数据库
	dinfo := model.Users{
		Username: info.User,
		Passwd:   info.Passwd,
		Name:     info.FileName, // 无后缀
		Size:     uint(fi.Size()),
		Route:    filePath,
		//Time1: info.Expiry,
	}
	model.Createuser(dinfo) // 数据库一条新纪录
	return c.HTML(http.StatusOK, fmt.Sprintf("<p>文件上传成功: %s</p>", file.Filename))
}

/*
 输入：前端提供的文件链接，
 返回：一个可供URL访问的链接（string）
*/
func SendFile(c echo.Context) error {
	info := new(File)
	if err := c.Bind(info); err != nil {
		return err
	}

	// 判断需不需要密码
	if info.FileType == "" {
		info.FileType = "txt"
	}

	if !model.Find(info.FileLink, info.SessionId) {
		// 没有sessionId（第一次访问）
		cookie, err := c.Cookie("User")
		if err != nil {
			return err
		}
		if cookie.Value != info.FileLink {
			return err // you wenti
		}
	}

	filePath := "./files/" + info.FileType + "/" + info.FileName + "." + info.FileType
	data:=readFile(filePath)
	c.JSON(http.StatusOK, info)
	return response.SendResponse(c, http.StatusOK, "msg",info.FileType, data)
	//return c.HTML(http.StatusOK, fmt.Sprintf("<p>文件上传成功: %s</p>", file.Filename))
	//return nil
}

func readFile(filePath string) string{
	src, err := os.Open(filePath)
	if err != nil {
		fmt.Println(err)
	}
	fi, err := src.Stat()
	if err != nil {
		fmt.Println(err)
	}

	defer func() {
		src.Close()
	}()

	data := make([]byte, fi.Size())
	_, err = src.Read(data)
	if err != nil {
		fmt.Println(err)
	}
	// 信息隐去
	//c.JSON(http.StatusOK, info)

	return string(data)
}



func RecvText(c echo.Context) error {
	text := new(Text)
	if err := c.Bind(text); err != nil {
		fmt.Println(err)
		return err
	}
	//return text.text
	return nil
}

func SendText(conn net.Conn, text Text) error {
	buf := []byte(text.text)
	_, err := conn.Write(buf[:])
	if err != nil {
		fmt.Println(err)
		return err
	}
	return nil
}

// 如果没有对应文件夹就建立
func catalogBuild(fileType string) error {
	err := os.Mkdir("pastebin/backend/files/"+fileType, 0666)
	if err != nil {
		return err
	}
	return nil
}

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func IdGen(n int) string {
	b := make([]rune, n)
	rand.Seed(time.Now().UnixNano())
	//for i:=0;i<n;i++{
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}
