package mysql

import (
	"context"

	"gorm.io/gorm"

	v1 "github.com/pingcap-inc/security/model/v1"
)

type wiki struct {
	db *gorm.DB
}

func newWiki(ds *datastore) *wiki {
	return &wiki{db: ds.db}
}

func (w *wiki) GetWikiSpace(_ context.Context) (wikiSpaces []v1.WikiSpace, err error) {
	err = w.db.Find(&wikiSpaces).Error

	return
}

func (w *wiki) GetWikiSpaceBySpaceID(_ context.Context, spaceID string) (wikiSpace v1.WikiSpace, err error) {
	err = w.db.Where("space_id = ?", spaceID).First(&wikiSpace).Error

	return
}

func (w *wiki) SaveDelWikiSpaces(_ context.Context, updateWikiSpaces, delWikiSpaces []v1.WikiSpace) error {
	tx := w.db.Begin()
	for _, wikiSpace := range updateWikiSpaces {
		err := tx.Save(&wikiSpace).Error
		if err != nil {
			tx.Rollback()

			return err
		}
	}

	for _, wikiSpace := range delWikiSpaces {
		err := tx.Where("space_id = ?", wikiSpace.SpaceID).Delete(&wikiSpace).Error
		if err != nil {
			tx.Rollback()

			return err
		}
	}

	tx.Commit()

	return nil
}

func (w *wiki) GetWikiDocs(_ context.Context) (wikiDocs []v1.WikiDoc, err error) {
	err = w.db.Find(&wikiDocs).Error

	return
}

func (w *wiki) GetWikiDocByDocID(_ context.Context, docID string) (wikiDoc v1.WikiDoc, err error) {
	err = w.db.Where("doc_id = ?", docID).First(&wikiDoc).Error

	return
}

func (w *wiki) GetWikiDocsByLevel(_ context.Context, level int) (wikiDoc []v1.WikiDoc, err error) {
	err = w.db.Where("level > ?", level).Find(&wikiDoc).Error

	return
}

func (w *wiki) UpdateWikiDocs(_ context.Context, wikiDocs []v1.WikiDoc) error {
	for _, doc := range wikiDocs {
		err := w.db.Model(&doc).Updates(doc).Error
		if err != nil {
			return err
		}
	}

	return nil
}

func (w *wiki) SaveDelWikiDocs(_ context.Context, updateWikiDocs, delWikiDocs []v1.WikiDoc) error {
	tx := w.db.Begin()
	for _, wikiDoc := range updateWikiDocs {
		err := tx.Save(&wikiDoc).Error
		if err != nil {
			tx.Rollback()
			return err
		}
	}

	for _, wikiDoc := range delWikiDocs {
		err := tx.Where("node_token = ?", wikiDoc.NodeToken).Delete(&wikiDoc).Error
		if err != nil {
			tx.Rollback()

			return err
		}
	}

	tx.Commit()

	return nil
}

func (w *wiki) SaveWikiDoc(_ context.Context, wikiDoc v1.WikiDoc) error {
	return w.db.Save(&wikiDoc).Error
}

func (w *wiki) GetWikiRegularByOrder(_ context.Context) (wikiRegular []v1.WikiRegular, err error) {
	err = w.db.Where("enable = 1").Order("level desc").Find(&wikiRegular).Error

	return
}

func (w *wiki) GetWikiDocsWithReason(_ context.Context, reason int) (wikiDocs []v1.WikiDoc, err error) {
	err = w.db.Where("reason", reason).Find(&wikiDocs).Error

	return
}

func (w *wiki) GetWikiDocsWithConfirm(_ context.Context) (wikiDocs []v1.WikiDoc, err error) {
	err = w.db.Where("permission = ? AND ( reason = ? or level < ?)", 0, 2, 3).Find(&wikiDocs).Error

	return
}

func (w *wiki) GetWikiDocWithoutContent(_ context.Context) (wikiDocs []v1.WikiDoc, err error) {
	err = w.db.Select("id,created_at,updated_at,deleted_at, space_id, parent_id, url, title, obj_token, node_token, owner, type, level, reason").Find(&wikiDocs).Error

	return
}

func (w *wiki) SaveWikiApprovals(_ context.Context, wikiApprovals []v1.WikiApproval) error {
	tx := w.db.Begin()
	for _, wikiApproval := range wikiApprovals {
		err := tx.Save(&wikiApproval).Error
		if err != nil {
			tx.Rollback()

			return err
		}
	}
	tx.Commit()

	return nil
}

func (w *wiki) SaveWikiApproval(_ context.Context, wikiApproval v1.WikiApproval) error {
	return w.db.Save(&wikiApproval).Error
}

func (w *wiki) GetWikiApprovals(_ context.Context) (wikiApprovals []v1.WikiApproval, err error) {
	err = w.db.Find(&wikiApprovals).Error

	return
}

func (w *wiki) GetWikiApprovalByStatus(_ context.Context, status int) (wikiApproval []v1.WikiApproval, err error) {
	err = w.db.Where("status = ?", 0).Find(&wikiApproval).Error

	return
}

func (w *wiki) GetWikiPermissions(_ context.Context) (wikiPermission []v1.WikiPermission, err error) {
	err = w.db.Find(&wikiPermission).Error

	return
}
