package api

import (
	"net/http"

	"github.com/tidbcloud/account/internel/dto"

	"google.golang.org/protobuf/types/known/timestamppb"

	"github.com/tidbcloud/account/internel/dao/entity"
	"github.com/tidbcloud/account/internel/svc/project"
	usersvc "github.com/tidbcloud/account/internel/svc/user"

	"go.uber.org/zap"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/account/admin/forms"
	"github.com/tidbcloud/tiinf/monitor/tilog"
)

// @Summary Delete Tenant Project
// @tags TenantProject
// @Accept  json
// @Produce json
// @Param org_id path string true "org_id"
// @Param project_id path string true "project_id"
// @Success 200 {object} forms.EmptyResponse
// @Router /orgs/{org_id}/projects/{project_id} [delete]
func DeleteProject(c *gin.Context) {
	req := forms.GetOrgIDAndProjectIDReq{}
	if err := c.ShouldBindUri(&req); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	tilog.Info(c.Request.Context(), "delete project", zap.Any("projectId", req.ProjectID))
	svc, _ := project.GetProjectSvc()
	err := svc.DeleteProject(c.Request.Context(), req.ProjectID)
	//err := tenantctx.DeleteProject(c.Request.Context(), entity.ID(req.OrgID), entity.ID(req.ProjectID))
	if err != nil {
		tilog.Warn(c.Request.Context(), "failed to delete project")
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	Success(c, nil, http.StatusOK)
}

// @Summary AddUserToProject
// @tags Project
// @Accept  json
// @Produce json
// @Param org_id path string  true "org_id"
// @Param org_id path string  true "user_id"
// @param req body forms.ProjectRoleReq true "project_role"
// @Success 200 {object} forms.EmptyResponse
// @Router /orgs/{org_id}/projects/{project_id}/users/{user_id} [post]
func AddUserToProject(c *gin.Context) {
	ctx := c.Request.Context()
	reqUri := forms.GetProjectIDAndUserIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	reqBody := forms.ProjectRoleReq{}
	if err := c.ShouldBindJSON(&reqBody); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	user, err := GetUserFromContext(c)
	if err != nil {
		tilog.Error(ctx, "failed to get user from context", zap.Error(err))
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	tilog.Info(ctx, "AddUserToProject req", zap.Any("req", reqUri), zap.Any("login_user", user.Email))
	//
	userSvc, _ := usersvc.GetUserSvc()
	err = userSvc.AddUserToProject(ctx, usersvc.AddUserToProjectReq{ProjectId: reqUri.ProjectID, UserId: reqUri.UserID, ProjectRole: reqBody.ProjectRole, OperatorId: user.ID.Uint64()})
	if err != nil {
		tilog.Info(ctx, "AddUserToProject", zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
	}

	Success(c, nil, http.StatusOK)
}

// @Summary RemoveUserFromeProject
// @tags Project
// @Accept  json
// @Produce json
// @Param org_id path string  true "org_id"
// @Param org_id path string  true "user_id"
// @param req body forms.ProjectRoleReq true "project_role"
// @Success 200 {object} forms.EmptyResponse
// @Router /orgs/{org_id}/projects/{project_id}/users/{user_id} [delete]
func RemoveUserFromeProject(c *gin.Context) {
	ctx := c.Request.Context()
	reqUri := forms.GetProjectIDAndUserIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	//user, err := GetUserFromContext(c)
	//if err != nil {
	//	tilog.Error(ctx, "failed to get user from context", zap.Error(err))
	//	Fail(c, err, http.StatusInternalServerError)
	//	return
	//}

	userSvc, _ := usersvc.GetUserSvc()
	err := userSvc.RemoveUserFromProject(ctx, reqUri.UserID, reqUri.UserID, reqUri.ProjectID)
	if err != nil {
		tilog.Error(ctx, "failed to RemoveUserFromProject", zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
	}
	tilog.Info(ctx, "RemoveUserFromProject success", zap.Any("user_id", reqUri.UserID), zap.Any("project_id", reqUri.ProjectID))

	Success(c, nil, http.StatusOK)
}

// @Summary GetOrgProjects
// @tags Project
// @Accept  json
// @Produce json
// @Param org_id path string  true "org_id"
// @param req query forms.GetOrgProjectsReq true "page query"
// @Success 200 {object} forms.GetOrgProjectsResp
// @Router /orgs/{org_id}/projects [get]
func GetOrgProjects(c *gin.Context) {
	ctx := c.Request.Context()
	reqUri := forms.GetOrgIDReq{}
	if err := c.ShouldBindUri(&reqUri); err != nil {
		tilog.Info(ctx, "failed to ShouldBindUri", zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
		return
	}
	req := forms.GetOrgProjectsReq{}
	if err := c.ShouldBindQuery(&req); err != nil {
		tilog.Info(ctx, "failed to ShouldBindQuery", zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
		return
	}

	params := dto.PageParams{
		Filters: map[string]interface{}{
			"tenant_id": reqUri.OrgID,               // db.Where("age = ?", 30)
			"status":    entity.ProjectStatusActive, // db.Where("age = ?", 30)
		},
		Order:    req.Order,
		SortBy:   req.SortBy,
		Page:     req.Pager.Page,
		PageSize: req.Pager.PageSize,
	}
	svc, _ := project.GetProjectSvc()

	paginator, err := svc.AdvancedListProjectsByPage(ctx, params)
	if err != nil {
		tilog.Info(ctx, "failed to ListActiveProjectsByOrgID", zap.Error(err))
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	projects := paginator.Data.([]project.Project)
	projectArr := make([]*forms.Project, 0)

	for _, p := range projects {
		bean := &forms.Project{

			ID:                  p.ID,
			Name:                p.Name,
			OrgId:               p.OrgID,
			UserCount:           p.UserCount,
			ActiveClustersCount: p.ActiveClustersCount,
			AwsCmekEnabled:      p.AwsCmekEnabled,
			CreatedAt:           timestamppb.New(p.CreatedAt),
		}

		projectArr = append(projectArr, bean)

	}

	resp := &forms.GetOrgProjectsResp{
		Total: paginator.Total,
		Items: projectArr,
	}
	Success(c, resp, http.StatusOK)
}
