// Package user — hesap (üyelik) yönetimi.
//
// Neden ayrı paket? Oturum, kullanıcı kaydı ve şifre doğrulama birbirinden
// BAĞIMSIZ birer iş kuralıdır. API katmanına gömülürse test edilemez ve
// ikinci bir istemci geldiğinde (CLI, mobil) tekrar yazılır.
//
// Güvenlik ilkeleri:
//   - Şifre HİÇBİR ZAMAN düz metin saklanmaz; yalnızca bcrypt özeti tutulur.
//   - Kullanıcı adı benzersizdir (veritabanı seviyesinde de tekrar edilir).
//   - Kullanıcı adı normalleştirilir: "Ahmet" ile "ahmet" AYNI hesaptır.
package user

import (
	"errors"
	"strings"
	"time"

	"fiko-ai/pkg/id"
)

// Role, kullanıcının sistem genelindeki yetki seviyesidir.
//
// Neden ayrı? Araç yetkileri (read/write/delete) KULLANICIYA özeldir ve
// GrantStore'da tutulur. Rol ise sistem genelidir: kim yeni hesap açabilir,
// kim araç tanımlayabilir, kim başkasının politikasını görebilir.
type Role string

const (
	// RoleUser normal üyedir: kendi verisine erişir, kendi araç yetkileri vardır.
	RoleUser Role = "user"
	// RoleAdmin yöneticidir: üye açma/kapama ve araç politikası görebilir.
	RoleAdmin Role = "admin"
)

// Valid rol mi?
func (r Role) Valid() bool { return r == RoleUser || r == RoleAdmin }

// User, bir hesabın kalıcı bilgisidir.
//
// PasswordHash JSON'a SERİLMEZ: dışarı sızan bir yanıt hash'i ifşa ederdi.
// `json:"-"` bunu garanti eder; API katmanı ayrıca View() kullanır.
type User struct {
	ID           string    `bson:"_id" json:"id"`
	Username     string    `bson:"username" json:"username"`
	PasswordHash string    `bson:"passwordHash" json:"-"`
	Role         Role      `bson:"role" json:"role"`
	Disabled     bool      `bson:"disabled" json:"disabled"`
	DisplayName  string    `bson:"displayName,omitempty" json:"displayName,omitempty"`
	CreatedAt    time.Time `bson:"createdAt" json:"createdAt"`
	LastLoginAt  time.Time `bson:"lastLoginAt,omitempty" json:"lastLoginAt,omitempty"`
}

// View, API'ye dönecek güvenli kopya döndürür (hash ve hassas alanlar yok).
func (u User) View() UserView {
	return UserView{
		ID:          u.ID,
		Username:    u.Username,
		Role:        u.Role,
		Disabled:    u.Disabled,
		DisplayName: u.DisplayName,
		CreatedAt:   u.CreatedAt,
		LastLoginAt: u.LastLoginAt,
	}
}

// UserView, API yanıtı için kullanıcının güvenli görünümüdür.
type UserView struct {
	ID          string    `json:"id"`
	Username    string    `json:"username"`
	Role        Role      `json:"role"`
	Disabled    bool      `json:"disabled"`
	DisplayName string    `json:"displayName,omitempty"`
	CreatedAt   time.Time `json:"createdAt"`
	LastLoginAt time.Time `json:"lastLoginAt,omitempty"`
}

// Kullanıcı adı kuralları.
const (
	minUsernameLen = 3
	maxUsernameLen = 32
	// minPasswordLen: kısa parolalar kaba kuvvetle kırılır. 8, kullanılabilir
	// en düşük sınır; daha uzun olanı zorlamak kullanıcıyı zayıf parolaya iter.
	minPasswordLen = 8
	maxPasswordLen = 128
)

// NormalizeUsername kullanıcı adını kanonik biçime getirir: kırpılır, küçük
// harfe indirilir. " Ahmet " ve "ahmet" AYNI hesap olur — aksi hâlde kullanıcı
// "ahmet" ve "ahmet" ile iki hesap açabilirdi.
func NormalizeUsername(s string) string {
	return strings.ToLower(strings.TrimSpace(s))
}

// ValidUsername, kullanıcı adının kurallara uyup uymadığını döner.
func ValidUsername(s string) error {
	n := NormalizeUsername(s)
	if len(n) < minUsernameLen {
		return errors.New("kullanıcı adı en az 3 karakter olmalı")
	}
	if len([]rune(n)) > maxUsernameLen {
		return errors.New("kullanıcı adı en fazla 32 karakter olabilir")
	}
	// Yalnızca harf, rakam, alt çizgi ve nokta: boşluk/Türkçe karakter/emoji
	// reddedilir çünkü bunlar dosya adı ve kimlik doğrulama sızıntısına yol açar.
	for _, r := range n {
		switch {
		case r >= 'a' && r <= 'z', r >= '0' && r <= '9':
		case r == '_' || r == '.' || r == '-':
		default:
			return errors.New("kullanıcı adı yalnızca harf, rakam, _ . - içerebilir")
		}
	}
	return nil
}

// ValidPassword parola gücünü denetler.
func ValidPassword(s string) error {
	if len(s) < minPasswordLen {
		return errors.New("parola en az 8 karakter olmalı")
	}
	if len(s) > maxPasswordLen {
		return errors.New("parola en fazla 128 karakter olabilir")
	}
	return nil
}

// New, doğrulanmış bir kullanıcı oluşturur (hash AYRI fonksiyonda üretilir).
func New(username, displayName string, role Role) (*User, error) {
	if err := ValidUsername(username); err != nil {
		return nil, err
	}
	if !role.Valid() {
		role = RoleUser
	}
	return &User{
		ID:          id.New("usr"),
		Username:    NormalizeUsername(username),
		Role:        role,
		DisplayName: strings.TrimSpace(displayName),
		CreatedAt:   time.Now().UTC(),
	}, nil
}
