package user

import (
	"errors"
	"strings"
	"system-altrak/internal/domain"
	actModule "system-altrak/internal/modules/activity"
	"system-altrak/pkg/utils"
)

type UserService interface {
	List() ([]domain.User, error)
	Create(user *domain.User, ip, userAgent string) error
	Update(user *domain.User, ip, userAgent string) error
	Delete(id, actorID uint, ip, userAgent string) error
}

type serviceImpl struct {
	repo UserRepository
	act  actModule.ActivityService
}

func NewService(repo UserRepository, act actModule.ActivityService) UserService {
	return &serviceImpl{repo: repo, act: act}
}

func (s *serviceImpl) List() ([]domain.User, error) {
	users, err := s.repo.List()
	if err != nil {
		return nil, err
	}
	for i := range users {
		users[i].PasswordHash = ""
	}
	return users, nil
}

func (s *serviceImpl) Create(user *domain.User, ip, userAgent string) error {
	// Simple validation
	user.FullName = strings.TrimSpace(user.FullName)
	user.Username = strings.TrimSpace(user.Username)
	if user.Username == "" || user.PasswordHash == "" {
		return errors.New("username and password are required")
	}
	if user.BranchID == 0 {
		user.BranchID = 1
	}

	normalizedRole, err := normalizeUserRole(user.Role)
	if err != nil {
		return err
	}
	user.Role = normalizedRole

	hash, err := utils.HashPassword(user.PasswordHash)
	if err != nil {
		return err
	}
	user.PasswordHash = hash
	if err := s.repo.Create(user); err != nil {
		return err
	}

	s.act.Log(0, user.Username, "SYSTEM", "USER_MGMT", "CREATE", "New personnel registered: "+user.FullName, ip, userAgent, user.BranchID)
	return nil
}

func (s *serviceImpl) Update(user *domain.User, ip, userAgent string) error {
	existing, err := s.repo.GetByID(user.ID)
	if err != nil {
		return err
	}

	user.FullName = strings.TrimSpace(user.FullName)
	user.Username = strings.TrimSpace(user.Username)

	normalizedRole, err := normalizeUserRole(user.Role)
	if err != nil {
		return err
	}

	existing.FullName = user.FullName
	existing.Username = user.Username
	existing.Role = normalizedRole
	if user.BranchID > 0 {
		existing.BranchID = user.BranchID
	}

	if user.PasswordHash != "" {
		hash, err := utils.HashPassword(user.PasswordHash)
		if err != nil {
			return err
		}
		existing.PasswordHash = hash
	}

	if err := s.repo.Update(existing); err != nil {
		return err
	}

	s.act.Log(existing.ID, existing.Username, "SYSTEM", "USER_MGMT", "UPDATE", "Personnel profile modified in matrix", ip, userAgent, existing.BranchID)
	return nil
}

func (s *serviceImpl) Delete(id, actorID uint, ip, userAgent string) error {
	if id == 0 {
		return errors.New("invalid user id")
	}

	existing, err := s.repo.GetByID(id)
	if err != nil {
		return err
	}

	if strings.EqualFold(existing.Role, "superadmin") {
		superadminCount, err := s.repo.CountByRole("superadmin")
		if err != nil {
			return err
		}
		if superadminCount <= 1 {
			return errors.New("cannot delete the last superadmin account")
		}
	}

	if err := s.repo.Delete(existing.ID); err != nil {
		return err
	}

	s.act.Log(actorID, existing.Username, "SYSTEM", "USER_MGMT", "DELETE", "Personnel profile deleted from matrix", ip, userAgent, existing.BranchID)
	return nil
}

func normalizeUserRole(role string) (string, error) {
	normalized := strings.ToLower(strings.TrimSpace(role))
	switch normalized {
	case "manager":
		return "admin", nil
	case "staff":
		return "user", nil
	case "admin", "user", "superadmin":
		return normalized, nil
	default:
		return "", errors.New("invalid role value")
	}
}
