package services

import (
	"bssapp-backend/models"
	"crypto/md5"
	"crypto/sha1"
	"encoding/hex"
	"log"
	"strings"

	"golang.org/x/crypto/bcrypt"
)

// CheckPasswordWithLegacy
// - SADECE doğrulama yapar
// - DB write YAPMAZ
// - Migration kararını caller verir
func CheckPasswordWithLegacy(user *models.User, plain string) bool {
	if user == nil {
		return false
	}

	if plain == "" {
		return false
	}

	stored := strings.TrimSpace(user.Upass)
	if stored == "" {
		return false
	}

	// 1️⃣ bcrypt hash mi?
	if isBcryptHash(stored) {
		candidates := make([]string, 0, 10)
		seen := map[string]struct{}{}
		add := func(v string) {
			if v == "" {
				return
			}
			if _, ok := seen[v]; ok {
				return
			}
			seen[v] = struct{}{}
			candidates = append(candidates, v)
		}

		add(plain)
		trimmed := strings.TrimSpace(plain)
		add(trimmed)

		bases := append([]string(nil), candidates...)
		for _, base := range bases {
			md5Sum := md5.Sum([]byte(base))
			md5Hex := hex.EncodeToString(md5Sum[:])
			add(md5Hex)
			add(strings.ToUpper(md5Hex))

			sha1Sum := sha1.Sum([]byte(base))
			sha1Hex := hex.EncodeToString(sha1Sum[:])
			add(sha1Hex)
			add(strings.ToUpper(sha1Hex))
		}

		var lastErr error
		for _, candidate := range candidates {
			if err := bcrypt.CompareHashAndPassword([]byte(stored), []byte(candidate)); err == nil {
				return true
			} else {
				lastErr = err
			}
			if encoded, ok := encodeLegacySingleByte(candidate); ok {
				if err := bcrypt.CompareHashAndPassword([]byte(stored), encoded); err == nil {
					return true
				} else {
					lastErr = err
				}
			}
		}
		if lastErr != nil {
			log.Printf(
				"LEGACY BCRYPT MISMATCH stored_len=%d candidates=%d last_err=%v",
				len(stored),
				len(candidates),
				lastErr,
			)
		}

		return false
	}

	// 2️⃣ TAM LEGACY — düz metin (eski kayıtlar)
	if stored == plain {
		return true
	}
	trimmed := strings.TrimSpace(plain)
	if trimmed != plain && trimmed != "" && stored == trimmed {
		return true
	}

	// 3️⃣ Legacy hash variants seen in old dfusr.upass data.
	if isHexDigest(stored, 32) {
		sumRaw := md5.Sum([]byte(plain))
		if strings.EqualFold(stored, hex.EncodeToString(sumRaw[:])) {
			return true
		}
		if trimmed != plain && trimmed != "" {
			sumTrim := md5.Sum([]byte(trimmed))
			if strings.EqualFold(stored, hex.EncodeToString(sumTrim[:])) {
				return true
			}
		}
	}

	if isHexDigest(stored, 40) {
		sumRaw := sha1.Sum([]byte(plain))
		if strings.EqualFold(stored, hex.EncodeToString(sumRaw[:])) {
			return true
		}
		if trimmed != plain && trimmed != "" {
			sumTrim := sha1.Sum([]byte(trimmed))
			if strings.EqualFold(stored, hex.EncodeToString(sumTrim[:])) {
				return true
			}
		}
	}

	return false
}

func isBcryptHash(s string) bool {
	return strings.HasPrefix(s, "$2a$") ||
		strings.HasPrefix(s, "$2b$") ||
		strings.HasPrefix(s, "$2y$")
}

func isHexDigest(s string, expectedLen int) bool {
	if len(s) != expectedLen {
		return false
	}
	for _, r := range s {
		if (r < '0' || r > '9') &&
			(r < 'a' || r > 'f') &&
			(r < 'A' || r > 'F') {
			return false
		}
	}
	return true
}

// encodeLegacySingleByte converts text to a Turkish-compatible single-byte
// representation (similar to Windows-1254 / ISO-8859-9) for legacy bcrypt data.
func encodeLegacySingleByte(s string) ([]byte, bool) {
	out := make([]byte, 0, len(s))
	for _, r := range s {
		switch r {
		case 'Ğ':
			out = append(out, 0xD0)
		case 'ğ':
			out = append(out, 0xF0)
		case 'İ':
			out = append(out, 0xDD)
		case 'ı':
			out = append(out, 0xFD)
		case 'Ş':
			out = append(out, 0xDE)
		case 'ş':
			out = append(out, 0xFE)
		default:
			if r >= 0 && r <= 0xFF {
				out = append(out, byte(r))
			} else {
				return nil, false
			}
		}
	}
	return out, true
}
