package handlers

import (
	"errors"
	"github.com/Pena-Co-Ltd/amocrm_templategen_back/dal/model"
	"github.com/gorilla/schema"
	"google.golang.org/api/drive/v3"
	"net/http"
)

type ReqGDiskSaveToken struct {
	State string
	Code  string
	Scope string
}

// GDiskSaveToken - сохраняет токен авторизации
func (h *Handlers) GDiskSaveToken(w http.ResponseWriter, r *http.Request) {
	var req ReqGDiskSaveToken

	err := r.ParseForm()
	if err != nil {
		h.reportError(w, err, http.StatusBadRequest)
		return
	}

	err = schema.NewDecoder().Decode(&req, r.Form)
	if err != nil {
		h.reportError(w, err, 500)
		return
	}

	// get user
	user := getJwtUser(r)
	if user == nil {
		h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized)
		return
	}

	// generate token

	token, err := h.GDisk.GetToken(r.Context(), req.Code)
	if err != nil {
		h.reportError(w, err, 500)
		return
	}

	gDisk, err := h.GDisk.NewClient(r.Context(), token)
	if err != nil {
		h.reportError(w, err, http.StatusInternalServerError)
		return
	}

	token = gDisk.Token

	gDiskUser, err := gDisk.GetUserInfo()
	if err != nil {
		h.reportError(w, err, http.StatusInternalServerError)
		return
	}

	// Make default directories in Google Drive
	gDiskData, err := h.dal.GDisk.GetByEmail(r.Context(), gDiskUser.EmailAddress)

	var templateId, saveId string
	if gDiskData != nil {
		templateId = gDiskData.TemplateFolderID
		saveId = gDiskData.SaveFolderID
	}

	templateId, saveId, err = gDisk.MakeDefaultDirs(templateId, saveId)
	if err != nil {
		h.reportError(w, err, http.StatusInternalServerError)
		return
	}

	gUser, err := gDisk.GetUserInfo()

	if err != nil {
		h.reportError(w, err, http.StatusInternalServerError)
		return
	}

	// Insert/Update token in DB
	_, err = h.dal.GDisk.InsertOrUpdate(r.Context(), &model.GDisk{
		UserID:           user.UserID,
		DisplayName:      gUser.DisplayName,
		Email:            gUser.EmailAddress,
		PhotoLink:        gUser.PhotoLink,
		AccessToken:      token.AccessToken,
		RefreshToken:     token.RefreshToken,
		ExpiresIn:        token.Expiry,
		TokenType:        token.TokenType,
		TemplateFolder:   "templategen/templates",
		TemplateFolderID: templateId,
		SaveFolder:       "templategen/saved",
		SaveFolderID:     saveId,
	})

	if err != nil {
		h.reportError(w, err, http.StatusInternalServerError)
		return
	}
}

func (h *Handlers) GDiskGetFile(w http.ResponseWriter, r *http.Request) {

}

type ReqGDiskGetDirInfo struct {
	Email    string `json:"email"`               // Required. Google Email ?
	ID       string `json:"id"`                  // Folder id
	Name     string `json:"name,omitempty"`      // Folder name
	ParentID string `json:"parent_id,omitempty"` // Parent folder id
}

// GDiskGetDirInfo - возвращает данные по папке, включая список её файлов и папок
func (h *Handlers) GDiskGetDirInfo(w http.ResponseWriter, r *http.Request) {
	var req ReqGDiskGetDirInfo

	err := decodePost(&req, r)
	if err != nil {
		h.reportError(w, err, http.StatusBadRequest)
		return
	}

	if req.Email == "" {
		h.reportError(w, errors.New("email required"), http.StatusBadRequest)
	}

	if req.ID == "" && req.Name == "" {
		h.reportError(w, errors.New("id or name required"), http.StatusBadRequest)
		return
	}

	amoData := getAmoByJwt(r)
	user := getJwtUser(r)

	if amoData == nil && user == nil {
		h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized)
		return
	}

	gdiskInfo, err := h.dal.GDisk.GetByEmail(r.Context(), req.Email)
	if err != nil {
		h.reportError(w, err, http.StatusInternalServerError)
		return
	}

	if gdiskInfo == nil {
		h.reportError(w, errors.New("gdisk info not found"), http.StatusForbidden)
		return
	}

	client, err := h.GDisk.NewClient(r.Context(), gdiskInfo.Token())
	if err != nil {
		h.reportError(w, err, http.StatusForbidden)
		return
	}

	var res []*drive.File

	if req.Name != "" {
		res, err = client.GetResourceByName(req.Name, req.ParentID)
		if err != nil {
			h.reportError(w, err, http.StatusInternalServerError)
			return
		}
	}

	dir, err := client.GetResources(res[0].Id)
	if err != nil {
		h.reportError(w, err, http.StatusInternalServerError)
		return
	}

	sendResponse(w, 200, dir)

}

type ReqGDiskGetDirTemplate struct {
	Email string `json:"email"` // Required. Google Email ?
}

// GDiskGetDirTemplate - возвращает данные по папке template, включая список её файлов и папок
func (h *Handlers) GDiskGetDirTemplate(w http.ResponseWriter, r *http.Request) {
	var req ReqGDiskGetDirTemplate

	err := decodePost(&req, r)
	if err != nil {
		h.reportError(w, err, http.StatusBadRequest)
		return
	}

	if req.Email == "" {
		h.reportError(w, errors.New("email required"), http.StatusBadRequest)
	}

	amoData := getAmoByJwt(r)
	user := getJwtUser(r)

	if amoData == nil && user == nil {
		h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized)
		return
	}

	gdiskInfo, err := h.dal.GDisk.GetByEmail(r.Context(), req.Email)
	if err != nil {
		h.reportError(w, err, http.StatusInternalServerError)
		return
	}

	if gdiskInfo == nil {
		h.reportError(w, errors.New("gdisk info not found"), http.StatusForbidden)
		return
	}

	if gdiskInfo.Token() == nil {
		h.reportError(w, errors.New("google token invalid"), http.StatusForbidden)
		return
	}

	client, err := h.GDisk.NewClient(r.Context(), gdiskInfo.Token())
	if err != nil {
		h.reportError(w, err, http.StatusInternalServerError)
		return
	}

	dir, err := client.GetResources(gdiskInfo.TemplateFolderID)
	if err != nil {
		h.reportError(w, err, http.StatusInternalServerError)
		return
	}

	sendResponse(w, 200, dir)
}

// GDiskGetList - возвращает список хранилищ Google закрепленных за пользователем по его UserID из JWT
func (h *Handlers) GDiskGetList(w http.ResponseWriter, r *http.Request) {
	amoData := getAmoByJwt(r)
	user := getJwtUser(r)

	if amoData == nil && user == nil {
		h.reportError(w, ErrorUnauthorized, http.StatusUnauthorized)
		return
	}

	var userID string
	if user != nil {
		userID = user.UserID
	} else {
		userID = amoData.UserID
	}

	gdiskInfo, err := h.dal.GDisk.GetListByUserID(r.Context(), userID)
	if err != nil {
		h.reportError(w, err, http.StatusInternalServerError)
		return
	}

	sendResponse(w, http.StatusOK, gdiskInfo)
}

func (h *Handlers) GDiskMkDir(w http.ResponseWriter, r *http.Request) {

}

func (h *Handlers) GDiskDelDir(w http.ResponseWriter, r *http.Request) {

}
