// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package context

import (
	"fmt"
	"image/color"
	"sync"

	"gitea.dev/modules/cache"
	"gitea.dev/modules/hcaptcha"
	"gitea.dev/modules/log"
	"gitea.dev/modules/mcaptcha"
	"gitea.dev/modules/recaptcha"
	"gitea.dev/modules/setting"
	"gitea.dev/modules/templates"
	"gitea.dev/modules/turnstile"

	"gitea.com/go-chi/captcha"
)

var (
	imageCaptchaOnce sync.Once
	cpt              *captcha.Captcha
)

// GetImageCaptcha returns global image captcha
func GetImageCaptcha() *captcha.Captcha {
	imageCaptchaOnce.Do(func() {
		cpt = captcha.NewCaptcha(captcha.Options{
			SubURL: setting.AppSubURL,
			// Use a color palette with high contrast colors suitable for both light and dark modes
			// These colors provide good visibility and readability in both themes
			ColorPalette: color.Palette{
				color.RGBA{R: 234, G: 67, B: 53, A: 255},  // Bright red
				color.RGBA{R: 66, G: 133, B: 244, A: 255}, // Medium blue
				color.RGBA{R: 52, G: 168, B: 83, A: 255},  // Green
				color.RGBA{R: 251, G: 188, B: 5, A: 255},  // Yellow/gold
				color.RGBA{R: 171, G: 71, B: 188, A: 255}, // Purple
			},
		})
		cpt.Store = cache.GetCache().ChiCache()
	})
	return cpt
}

const (
	gRecaptchaResponseField  = "g-recaptcha-response"
	hCaptchaResponseField    = "h-captcha-response"
	mCaptchaResponseField    = "mcaptcha__token" // this form key is hard-coded in the mcaptcha frontend library
	cfTurnstileResponseField = "cf-turnstile-response"
)

// VerifyCaptcha verifies Captcha data
// No-op if captchas are not enabled
func VerifyCaptcha(ctx *Context, tpl templates.TplName, form any) {
	if !setting.Service.EnableCaptcha {
		return
	}

	var valid bool
	var err error
	switch setting.Service.CaptchaType {
	case setting.ImageCaptcha:
		valid = GetImageCaptcha().VerifyReq(ctx.Req)
	case setting.ReCaptcha:
		valid, err = recaptcha.Verify(ctx, ctx.Req.Form.Get(gRecaptchaResponseField))
	case setting.HCaptcha:
		valid, err = hcaptcha.Verify(ctx, ctx.Req.Form.Get(hCaptchaResponseField))
	case setting.MCaptcha:
		valid, err = mcaptcha.Verify(ctx, ctx.Req.Form.Get(mCaptchaResponseField))
	case setting.CfTurnstile:
		valid, err = turnstile.Verify(ctx, ctx.Req.Form.Get(cfTurnstileResponseField))
	default:
		ctx.ServerError("Unknown Captcha Type", fmt.Errorf("unknown Captcha Type: %s", setting.Service.CaptchaType))
		return
	}
	if err != nil {
		log.Debug("Captcha Verify failed: %v", err)
	}

	if !valid {
		ctx.Data["Err_Captcha"] = true
		ctx.RenderWithErrDeprecated(ctx.Tr("form.captcha_incorrect"), tpl, form)
	}
}
