package repo

import (
	"sort"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/auth"
	"code.gitea.io/gitea/modules/base"
	"code.gitea.io/gitea/modules/context"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/setting"
)

const (
	tplIndex base.TplName = "repo/datasets/index"
)

// MustEnableDataset check if repository enable internal dataset
func MustEnableDataset(ctx *context.Context) {
	if !ctx.Repo.CanRead(models.UnitTypeDatasets) {
		ctx.NotFound("MustEnableDataset", nil)
		return
	}
}

func newFilterPrivateAttachments(ctx *context.Context, list []*models.Attachment, repo *models.Repository) []*models.Attachment {

	if ctx.Repo.CanWrite(models.UnitTypeDatasets) {
		log.Info("can write.")
		return list
	} else {
		if repo.Owner == nil {
			repo.GetOwner()
		}
		permission := false
		if repo.Owner.IsOrganization() && ctx.User != nil {
			if repo.Owner.IsUserPartOfOrg(ctx.User.ID) {
				log.Info("user is member of org.")
				permission = true
			}
		}
		if !permission && ctx.User != nil {
			isCollaborator, _ := repo.IsCollaborator(ctx.User.ID)
			if isCollaborator {
				log.Info("Collaborator user may visit the attach.")
				permission = true
			}
		}

		var publicList []*models.Attachment
		for _, attach := range list {
			if !attach.IsPrivate {
				publicList = append(publicList, attach)
			} else {
				if permission {
					publicList = append(publicList, attach)
				}
			}
		}
		return publicList
	}
}

func QueryDataSet(ctx *context.Context) []*models.Attachment {
	repo := ctx.Repo.Repository

	dataset, err := models.GetDatasetByRepo(repo)
	if err != nil {
		log.Error("zou  not found dataset 1")
		ctx.NotFound("GetDatasetByRepo", err)
		return nil
	}

	if ctx.Query("type") == "" {
		log.Error("zou  not found  type 2")
		ctx.NotFound("type error", nil)
		return nil
	}
	err = models.GetDatasetAttachments(ctx.QueryInt("type"), ctx.IsSigned, ctx.User, dataset)
	if err != nil {
		ctx.ServerError("GetDatasetAttachments", err)
		return nil
	}
	attachments := newFilterPrivateAttachments(ctx, dataset.Attachments, repo)

	ctx.Data["SortType"] = ctx.Query("sort")
	switch ctx.Query("sort") {
	case "newest":
		sort.Slice(attachments, func(i, j int) bool {
			return attachments[i].CreatedUnix > attachments[j].CreatedUnix
		})
	case "oldest":
		sort.Slice(attachments, func(i, j int) bool {
			return attachments[i].CreatedUnix < attachments[j].CreatedUnix
		})
	default:
		ctx.Data["SortType"] = "newest"
		sort.Slice(attachments, func(i, j int) bool {
			return attachments[i].CreatedUnix > attachments[j].CreatedUnix
		})
	}
	return attachments
}

func DatasetIndex(ctx *context.Context) {
	log.Info("dataset index 1")
	MustEnableDataset(ctx)

	repo := ctx.Repo.Repository

	dataset, err := models.GetDatasetByRepo(repo)
	if err != nil {
		log.Error("query dataset, not found repo.")
		ctx.NotFound("GetDatasetByRepo", err)
		return
	}

	if ctx.Query("type") == "" {
		log.Error("query dataset, not found param type")
		ctx.NotFound("type error", nil)
		return
	}
	err = models.GetDatasetAttachments(ctx.QueryInt("type"), ctx.IsSigned, ctx.User, dataset)
	if err != nil {
		ctx.ServerError("GetDatasetAttachments", err)
		return
	}

	attachments := newFilterPrivateAttachments(ctx, dataset.Attachments, repo)

	ctx.Data["SortType"] = ctx.Query("sort")
	switch ctx.Query("sort") {
	case "newest":
		sort.Slice(attachments, func(i, j int) bool {
			return attachments[i].CreatedUnix > attachments[j].CreatedUnix
		})
	case "oldest":
		sort.Slice(attachments, func(i, j int) bool {
			return attachments[i].CreatedUnix < attachments[j].CreatedUnix
		})
	default:
		ctx.Data["SortType"] = "newest"
		sort.Slice(attachments, func(i, j int) bool {
			return attachments[i].CreatedUnix > attachments[j].CreatedUnix
		})
	}

	ctx.Data["PageIsDataset"] = true
	ctx.Data["Title"] = ctx.Tr("dataset.show_dataset")
	ctx.Data["Link"] = ctx.Repo.RepoLink + "/datasets"
	ctx.Data["dataset"] = dataset
	ctx.Data["Attachments"] = attachments
	ctx.Data["IsOwner"] = true
	ctx.Data["StoreType"] = setting.Attachment.StoreType
	ctx.Data["Type"] = ctx.QueryInt("type")

	renderAttachmentSettings(ctx)

	ctx.HTML(200, tplIndex)
}

func EditDatasetPost(ctx *context.Context, form auth.EditDatasetForm) {
	ctx.Data["PageIsDataset"] = true

	ctx.Data["Title"] = ctx.Tr("dataset.edit_dataset")

	rel, err := models.GetDatasetByID(form.ID)
	ctx.Data["dataset"] = rel

	if err != nil {
		ctx.ServerError("GetDataset", err)
		return
	}

	if ctx.HasError() {
		ctx.Data["Error"] = true
		ctx.HTML(200, tplIndex)
		return
	}

	rel.Title = form.Title
	rel.Description = form.Description
	rel.Category = form.Category
	rel.Task = form.Task
	rel.License = form.License
	if err = models.UpdateDataset(models.DefaultDBContext(), rel); err != nil {
		ctx.Data["Error"] = true
		ctx.HTML(200, tplIndex)
		log.Error("%v", err)
	}
	ctx.Redirect(ctx.Repo.RepoLink + "/datasets?type=" + form.Type)
}
