package check_ownership

import (
	"fmt"
	"gitea.pena/SQuiz/common/dal"
	"gitea.pena/SQuiz/common/middleware"
	"github.com/gofiber/fiber/v2"
	"regexp"
	"strconv"
)

type Owner interface {
	Check(ctx *fiber.Ctx) (bool, error)
}

type OwnerShip struct {
	dal *dal.DAL
}

func NewOwnerShip(dal *dal.DAL) *OwnerShip {
	return &OwnerShip{
		dal: dal,
	}
}

// имеем id квиза и id аккаунта проверяем что квиз принадлежит аккаунту
func (o *OwnerShip) CheckQuiz(ctx *fiber.Ctx) (bool, error) {
	accountId, ok := middleware.GetAccountId(ctx)
	if !ok {
		return false, fiber.NewError(fiber.StatusUnauthorized, "account id is required")
	}

	quizIDStr := ctx.Params("quizID")
	var quizID uint64
	var err error

	if quizIDStr != "" {
		quizID, err = strconv.ParseUint(quizIDStr, 10, 64)
		if err != nil {
			return false, fiber.NewError(fiber.StatusBadRequest, "invalid quiz ID")
		}
	}

	if quizIDStr == "" {
		var body struct {
			QuizID uint64 `json:"quiz_id"`
		}

		if err := ctx.BodyParser(&body); err != nil {
			return false, fiber.NewError(fiber.StatusBadRequest, "invalid request data")
		}

		quizID = body.QuizID
	}

	isOwner, err := o.dal.QuizRepo.CheckQuizOwner(ctx.Context(), accountId, quizID)
	if err != nil {
		return false, fiber.NewError(fiber.StatusInternalServerError, err.Error())
	}

	return isOwner, nil
}

// имеем id результата и id аккаунта проверяем с помощью CheckResultOwner
func (o *OwnerShip) CheckResult(ctx *fiber.Ctx) (bool, error) {
	accountID, ok := middleware.GetAccountId(ctx)
	if !ok {
		return false, fiber.NewError(fiber.StatusUnauthorized, "account id is required")
	}

	// todo интересная штука заметил что параметры на этапе промежуточного по не существует, оч сильно усложняет надо будет обдумать
	resultID, err := strconv.ParseUint(ctx.Params("resultID"), 10, 64)
	if err != nil {
		return false, fiber.NewError(fiber.StatusBadRequest, "invalid result ID format")
	}

	isOwner, err := o.dal.ResultRepo.CheckResultOwner(ctx.Context(), resultID, accountID)
	if err != nil {
		return false, fiber.NewError(fiber.StatusInternalServerError, err.Error())
	}

	return isOwner, nil
}

// имеем id вопроса и id аккаунта проверяем что квиз этого вопроса относится к аккаунту
func (o *OwnerShip) CheckQuestion(ctx *fiber.Ctx) (bool, error) {
	accountID, ok := middleware.GetAccountId(ctx)
	if !ok {
		return false, fiber.NewError(fiber.StatusUnauthorized, "account id is required")
	}

	var body struct {
		QuestionID uint64 `json:"id"`
	}

	if err := ctx.BodyParser(&body); err != nil {
		return false, fiber.NewError(fiber.StatusBadRequest, "invalid request data")
	}

	isOwner, err := o.dal.QuestionRepo.CheckQuestionOwner(ctx.Context(), accountID, body.QuestionID)
	if err != nil {
		return false, fiber.NewError(fiber.StatusInternalServerError, err.Error())
	}
	return isOwner, nil
}

// проверка для лид таргета надо проверить что в лид имеет отношение к аккаунту
func (o *OwnerShip) CheckLeadTarget(ctx *fiber.Ctx) (bool, error) {
	return true, nil
}

func (o *OwnerShip) CheckStatistic(ctx *fiber.Ctx) (bool, error) {
	return true, nil
}

var pathCheckMap = map[*regexp.Regexp]func(*OwnerShip, *fiber.Ctx) (bool, error){
	regexp.MustCompile(`^POST /question/create$`):   (*OwnerShip).CheckQuiz,     // quiz_id
	regexp.MustCompile(`^POST /question/getList$`):  (*OwnerShip).CheckQuiz,     // quiz_id
	regexp.MustCompile(`^PATCH /question/edit$`):    (*OwnerShip).CheckQuestion, // id
	regexp.MustCompile(`^POST /question/copy$`):     (*OwnerShip).CheckQuiz,     // quiz_id
	regexp.MustCompile(`^POST /question/history$`):  (*OwnerShip).CheckQuestion, // id
	regexp.MustCompile(`^DELETE /question/delete$`): (*OwnerShip).CheckQuestion, // id

	//regexp.MustCompile(`^GET /result/\d+$`): (*OwnerShip).CheckResult, // resultID в роуте (id ответа)
	// todo POST /results/getResults/16675
	regexp.MustCompile(`^POST /results/getResults/\d+$`): (*OwnerShip).CheckQuiz, // quizID в роуте
	// todo POST /results/16675/export
	regexp.MustCompile(`^POST /results/\d+/export$`): (*OwnerShip).CheckQuiz, // quizID в роуте

	// todo все роутф статистики клиентские
	regexp.MustCompile(`^POST /statistic/\d+/devices$`):   (*OwnerShip).CheckStatistic,
	regexp.MustCompile(`^POST /statistic/\d+/general$`):   (*OwnerShip).CheckStatistic,
	regexp.MustCompile(`^POST /statistic/\d+/questions$`): (*OwnerShip).CheckStatistic,

	// пока не в приоритете todo
	regexp.MustCompile(`^DELETE /account/account/leadtarget/\d+$`): (*OwnerShip).CheckLeadTarget,
	regexp.MustCompile(`^PUT /account/account/leadtarget$`):        (*OwnerShip).CheckLeadTarget,
}

// todo подключить проверить
func OwnerShipMiddleware(o *OwnerShip) fiber.Handler {
	return func(c *fiber.Ctx) error {
		methodPath := fmt.Sprintf("%s %s", c.Method(), c.Path())

		fmt.Println(methodPath)

		fmt.Println(c.Params("resultID"))

		for re, f := range pathCheckMap {
			if re.MatchString(methodPath) {
				ok, err := f(o, c)
				if err != nil {
					return err
				}
				if !ok {
					return fiber.NewError(fiber.StatusForbidden, "access denied")
				}

				break
			}
		}

		return c.Next()
	}
}
