package lanzou

import (
	"fmt"
	"github.com/Xhofe/alist/drivers/base"
	"github.com/Xhofe/alist/model"
	log "github.com/sirupsen/logrus"
	"net/url"
	"regexp"
	"strconv"
	"time"
)

func (driver *Lanzou) FormatFile(file *LanZouFile) *model.File {
	now := time.Now()
	f := &model.File{
		Id:        file.Id,
		Name:      file.Name,
		Driver:    driver.Config().Name,
		SizeStr:   file.Size,
		TimeStr:   file.Time,
		UpdatedAt: &now,
	}
	if file.Folder {
		f.Id = file.FolId
	} else {
		f.Name = file.NameAll
	}
	f.Type = file.GetType()
	return f
}

type LanZouFilesResp struct {
	Zt   int          `json:"zt"`
	Info interface{}  `json:"info"`
	Text []LanZouFile `json:"text"`
}

func (driver *Lanzou) GetFiles(folderId string, account *model.Account) ([]LanZouFile, error) {
	if account.InternalType == "cookie" {
		files := make([]LanZouFile, 0)
		var resp LanZouFilesResp
		// folders
		res, err := base.RestyClient.R().SetResult(&resp).SetHeader("Cookie", account.AccessToken).
			SetFormData(map[string]string{
				"task":      "47",
				"folder_id": folderId,
			}).Post("https://pc.woozooo.com/doupload.php")
		if err != nil {
			return nil, err
		}
		log.Debug(res.String())
		if resp.Zt != 1 && resp.Zt != 2 {
			return nil, fmt.Errorf("%v", resp.Info)
		}
		for _, file := range resp.Text {
			file.Folder = true
			files = append(files, file)
		}
		// files
		pg := 1
		for {
			_, err = base.RestyClient.R().SetResult(&resp).SetHeader("Cookie", account.AccessToken).
				SetFormData(map[string]string{
					"task":      "5",
					"folder_id": folderId,
					"pg":        strconv.Itoa(pg),
				}).Post("https://pc.woozooo.com/doupload.php")
			if err != nil {
				return nil, err
			}
			if resp.Zt != 1 {
				return nil, fmt.Errorf("%v", resp.Info)
			}
			if len(resp.Text) == 0 {
				break
			}
			files = append(files, resp.Text...)
			pg++
		}
		return files, nil
	} else {
		return driver.GetFilesByUrl(account)
	}
}

func (driver *Lanzou) GetFilesByUrl(account *model.Account) ([]LanZouFile, error) {
	files := make([]LanZouFile, 0)
	shareUrl := account.SiteUrl
	u, err := url.Parse(shareUrl)
	if err != nil {
		return nil, err
	}
	res, err := base.RestyClient.R().Get(shareUrl)
	if err != nil {
		return nil, err
	}
	lxArr := regexp.MustCompile(`'lx':(.+?),`).FindStringSubmatch(res.String())
	if len(lxArr) == 0 {
		return nil, fmt.Errorf("get empty page")
	}
	lx := lxArr[1]
	fid := regexp.MustCompile(`'fid':(.+?),`).FindStringSubmatch(res.String())[1]
	uid := regexp.MustCompile(`'uid':'(.+?)',`).FindStringSubmatch(res.String())[1]
	rep := regexp.MustCompile(`'rep':'(.+?)',`).FindStringSubmatch(res.String())[1]
	up := regexp.MustCompile(`'up':(.+?),`).FindStringSubmatch(res.String())[1]
	ls := ""
	if account.Password != "" {
		ls = regexp.MustCompile(`'ls':(.+?),`).FindStringSubmatch(res.String())[1]
	}
	tName := regexp.MustCompile(`'t':(.+?),`).FindStringSubmatch(res.String())[1]
	kName := regexp.MustCompile(`'k':(.+?),`).FindStringSubmatch(res.String())[1]
	t := regexp.MustCompile(`var ` + tName + ` = '(.+?)';`).FindStringSubmatch(res.String())[1]
	k := regexp.MustCompile(`var ` + kName + ` = '(.+?)';`).FindStringSubmatch(res.String())[1]
	pg := 1
	for {
		var resp LanZouFilesResp
		res, err = base.RestyClient.R().SetResult(&resp).SetFormData(map[string]string{
			"lx":  lx,
			"fid": fid,
			"uid": uid,
			"pg":  strconv.Itoa(pg),
			"rep": rep,
			"t":   t,
			"k":   k,
			"up":  up,
			"ls":  ls,
			"pwd": account.Password,
		}).Post(fmt.Sprintf("https://%s/filemoreajax.php", u.Host))
		if err != nil {
			log.Debug(err)
			break
		}
		log.Debug(res.String())
		if resp.Zt != 1 {
			return nil, fmt.Errorf("%v", resp.Info)
		}
		if len(resp.Text) == 0 {
			break
		}
		pg++
		time.Sleep(time.Second)
		files = append(files, resp.Text...)
	}
	return files, nil
}

//type LanzouDownInfo struct {
//	FId    string `json:"f_id"`
//	IsNewd string `json:"is_newd"`
//}

// GetDownPageId 获取下载页面的ID
func (driver *Lanzou) GetDownPageId(fileId string, account *model.Account) (string, string, error) {
	var resp DownPageResp
	res, err := base.RestyClient.R().SetResult(&resp).SetHeader("Cookie", account.AccessToken).
		SetFormData(map[string]string{
			"task":    "22",
			"file_id": fileId,
		}).Post("https://pc.woozooo.com/doupload.php")
	if err != nil {
		return "", "", err
	}
	log.Debug(res.String())
	if resp.Zt != 1 {
		return "", "", fmt.Errorf("%v", resp.Info)
	}
	return resp.Info.FId, resp.Info.Pwd, nil
}

type LanzouLinkResp struct {
	Dom string `json:"dom"`
	Url string `json:"url"`
	Zt  int    `json:"zt"`
}

func (driver *Lanzou) GetLink(downId string, pwd string, account *model.Account) (string, error) {
	shareUrl := account.SiteUrl
	u, err := url.Parse(shareUrl)
	if err != nil {
		return "", err
	}
	log.Debugln(fmt.Sprintf("https://%s/%s", u.Host, downId))
	res, err := base.RestyClient.R().Get(fmt.Sprintf("https://%s/%s", u.Host, downId))
	if err != nil {
		return "", err
	}
	iframe := regexp.MustCompile(`<iframe class="ifr2" name=".{2,20}" src="(.+?)"`).FindStringSubmatch(res.String())
	if len(iframe) == 0 {
		return driver.GetLinkWithPassword(downId, pwd, res.String(), account)
	}
	iframeUrl := fmt.Sprintf("https://%s%s", u.Host, iframe[1])
	res, err = base.RestyClient.R().Get(iframeUrl)
	if err != nil {
		return "", err
	}
	log.Debugln(res.String())
	ajaxdata := regexp.MustCompile(`var ajaxdata = '(.+?)'`).FindStringSubmatch(res.String())
	if len(ajaxdata) == 0 {
		return "", fmt.Errorf("get iframe empty page")
	}
	signs := ajaxdata[1]
	//sign := regexp.MustCompile(`var ispostdowns = '(.+?)';`).FindStringSubmatch(res.String())[1]
	sign := regexp.MustCompile(`'sign':'(.+?)',`).FindStringSubmatch(res.String())[1]
	//websign := regexp.MustCompile(`'websign':'(.+?)'`).FindStringSubmatch(res.String())[1]
	websign := ""
	websignR := regexp.MustCompile(`var websign = '(.+?)'`).FindStringSubmatch(res.String())
	if len(websignR) > 1 {
		websign = websignR[1]
	}
	//websign := ""
	//websignkey := regexp.MustCompile(`'websignkey':'(.+?)'`).FindStringSubmatch(res.String())[1]
	websignkey := regexp.MustCompile(`var websignkey = '(.+?)';`).FindStringSubmatch(res.String())[1]
	var resp LanzouLinkResp
	form := map[string]string{
		"action":     "downprocess",
		"signs":      signs,
		"sign":       sign,
		"ves":        "1",
		"websign":    websign,
		"websignkey": websignkey,
	}
	log.Debugf("form: %+v", form)
	res, err = base.RestyClient.R().SetResult(&resp).
		SetHeader("origin", "https://"+u.Host).
		SetHeader("referer", iframeUrl).
		SetFormData(form).Post(fmt.Sprintf("https://%s/ajaxm.php", u.Host))
	log.Debug(res.String())
	if err != nil {
		return "", err
	}
	if resp.Zt == 1 {
		return resp.Dom + "/file/" + resp.Url, nil
	}
	return "", fmt.Errorf("failed get link")
}

func (driver *Lanzou) GetLinkWithPassword(downId string, pwd string, html string, account *model.Account) (string, error) {
	shareUrl := account.SiteUrl
	u, err := url.Parse(shareUrl)
	if err != nil {
		return "", err
	}
	if html == "" {
		log.Debugln(fmt.Sprintf("https://%s/%s", u.Host, downId))
		res, err := base.RestyClient.R().Get(fmt.Sprintf("https://%s/%s", u.Host, downId))
		if err != nil {
			return "", err
		}
		html = res.String()
	}

	data := regexp.MustCompile(`data : '(.+?)'\+pwd,`).FindStringSubmatch(html)[1] + pwd
	var resp LanzouLinkResp
	_, err = base.RestyClient.R().SetResult(&resp).SetHeaders(map[string]string{
		"Referer":      fmt.Sprintf("https://%s/%s", u.Host, downId),
		"Origin":       "https://" + u.Host,
		"content-type": "application/x-www-form-urlencoded",
	}).SetBody(data).Post(fmt.Sprintf("https://%s/ajaxm.php", u.Host))
	if err != nil {
		return "", err
	}
	if resp.Zt == 1 {
		return resp.Dom + "/file/" + resp.Url, nil
	}
	return "", fmt.Errorf("failed get link with password")
}

func init() {
	base.RegisterDriver(&Lanzou{})
}