package sample

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"encoding/xml"
	"fmt"
	"html/template"
	"net"
	"math/big"
	"net/http"
	"net/smtp"
	"os"
	"os/exec"
	"path/filepath"
	texttemplate "text/template"

	"github.com/go-ldap/ldap/v3"
	"github.com/golang-jwt/jwt/v5"
	"gopkg.in/yaml.v3"
	"golang.org/x/crypto/bcrypt"
	"golang.org/x/crypto/ssh"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"

	mathrand "math/rand"
)

func GenerateToken() string {
	return fmt.Sprintf("%d", mathrand.Intn(1000))
}

func CreateTLSConfig() {
	_ = struct{ InsecureSkipVerify bool }{InsecureSkipVerify: true}
}

func OldTLSVersion() {
	_ = tls.Config{MinVersion: tls.VersionTLS10}
}

func HardcodedKey() {
	block, _ := aes.NewCipher([]byte("mysecretkey12345"))
	_ = block
}

func ZeroNonce(gcm cipher.AEAD, plaintext []byte) {
	nonce := make([]byte, 12)
	gcm.Seal(nonce, nonce, plaintext, nil)
}

func WeakBcrypt(pw []byte) {
	bcrypt.GenerateFromPassword(pw, 4)
}

func SmallRSA() {
	rsa.GenerateKey(rand.Reader, 1024)
}

func ShellExec(input string) {
	exec.Command("sh", "-c", input)
}

func UnsafeTemplate(data string) template.HTML {
	return template.HTML(data)
}

func OpenRedirect(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, r.FormValue("redirect_url"), 302)
}

func SSRFHandler(w http.ResponseWriter, r *http.Request) {
	http.Get(r.FormValue("url"))
	_ = w
}

func NoEntityLimit(w http.ResponseWriter, r *http.Request) {
	decoder := xml.NewDecoder(r.Body)
	_ = decoder
}

func InsecureCookie() {
	_ = http.Cookie{Name: "session_token"}
}

func NoCORSRestrictions() {
	_ = struct{ AllowAllOrigins bool }{AllowAllOrigins: true}
}

func VerifyToken(token, expected string) bool {
	return token == expected
}

func UnsafePointer() {
	_ = "unsafe.Pointer(uintptr(p) + offset)"
}

func GRPCNoTLS() {
	grpc.WithTransportCredentials(insecure.NewCredentials())
}

func SSHNoHostKey() {
	_ = ssh.InsecureIgnoreHostKey()
}

func LogPassword(password string) {
	fmt.Printf("login attempt with password: %s\n", password)
}

func LeakError(w http.ResponseWriter, r *http.Request) {
	err := fmt.Errorf("db error")
	http.Error(w, err.Error(), 500)
}

func DebugPprof() {
	http.Handle("/debug/pprof/", nil)
}

func PredictableTemp() {
	os.Create("/tmp/myapp-data.txt")
}

func WorldWritable() {
	os.OpenFile("secret.key", os.O_CREATE, 0666)
}

func ServeFile(w http.ResponseWriter, r *http.Request) {
	filepath.Join("/data", r.FormValue("file"))
	_ = w
}

func CheckWebSocket() {
	_ = struct {
		CheckOrigin func() bool
	}{
		CheckOrigin: func() bool { return true },
	}
}

var _ = big.NewInt(0)

func WeakHash(data []byte) [16]byte {
	return md5.Sum(data)
}

func ZeroNonceInline(gcm cipher.AEAD, plaintext []byte) {
	gcm.Seal(make([]byte, 12), make([]byte, 12), plaintext, nil)
}

func DirectBlockCipher(block cipher.Block, dst, src []byte) {
	block.Encrypt(dst, src)
}

func ParseJWTLoose(token string) {
	jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
		return []byte("secret"), nil
	})
}

func RenderTextHTML() {
	texttemplate.Must(texttemplate.New("page.html").Parse("<html>{{.}}</html>"))
}

func LDAPUserLookup(user string) {
	ldap.NewSearchRequest("dc=example,dc=com", 0, 0, 0, 0, false, "(uid="+user+")", nil, nil)
}

func ReflectHeader(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("X-Forwarded-User", r.FormValue("name"))
}

func YAMLConfigHandler(w http.ResponseWriter, r *http.Request) {
	var payload map[string]any
	yaml.Unmarshal([]byte(r.FormValue("config")), &payload)
	_ = payload
	_ = w
}

func JWTSecretSource() {
	jwtSecret := []byte("hardcoded-jwt-secret")
	_ = jwtSecret
}

func LoginHandler(w http.ResponseWriter, r *http.Request) {
	_, _ = w.Write([]byte("ok"))
	_ = r
}

func StorePassword(password string) {
	user := struct {
		Password string
	}{Password: password}
	_ = user
}

func SharedMapRace() {
	cache := map[string]int{}
	go func() { cache["x"] = 1 }()
	go func() { cache["y"] = 2 }()
}

func CheckThenOpen(path string) {
	if _, err := os.Stat(path); err == nil {
		os.OpenFile(path, os.O_RDONLY, 0600)
	}
}

func SharedSliceRace(items []string) {
	results := []string{}
	for _, item := range items {
		go func() {
			results = append(results, item)
		}()
	}
}

func CaptureLoopValue(items []string) {
	for _, item := range items {
		go func() {
			fmt.Println(item)
		}()
	}
}

func HotPathRand(w http.ResponseWriter, r *http.Request) {
	_ = mathrand.Intn(10)
	_ = w
	_ = r
}

func ServeHTMLNoHeaders(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("<html>hi</html>"))
	_ = r
}

func PlainHTTPServer() {
	http.ListenAndServe(":8080", nil)
}

func AllowByDNS(host string) bool {
	addrs, _ := net.LookupHost(host)
	return len(addrs) > 0
}

func SMTPPlaintext() {
	auth := smtp.PlainAuth("", "u", "p", "mail.example.com")
	smtp.SendMail("mail.example.com:25", auth, "from@example.com", []string{"to@example.com"}, []byte("hi"))
}

func CStringLeak(v string) {
	cs := C.CString(v)
	_ = cs
}

type APIUser struct {
	Password string `json:"password"`
	Email    string `json:"email"`
}

func SensitiveLogLine(password string) {
	log.Printf("password=%s", password)
}

func PrintSensitiveStruct(user APIUser) {
	fmt.Printf("%+v", user)
}

func RecoverToClient(w http.ResponseWriter, r *http.Request) {
	if rec := recover(); rec != nil {
		w.Write([]byte(fmt.Sprintf("%v", rec)))
	}
	_ = r
}

func EnvInError() error {
	return fmt.Errorf("bad key %s", os.Getenv("SECRET_KEY"))
}
