package team

import (
	"context"
	"time"

	"Yimaru-Backend/internal/domain"

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

const bcryptCost = 10

func (s *Service) CreateTeamMember(ctx context.Context, req domain.CreateTeamMemberReq, createdBy *int64) (domain.TeamMember, error) {
	if !domain.TeamRole(req.TeamRole).IsValid() {
		return domain.TeamMember{}, domain.ErrInvalidTeamRole
	}

	if req.EmploymentType != "" && !domain.EmploymentType(req.EmploymentType).IsValid() {
		return domain.TeamMember{}, domain.ErrInvalidEmploymentType
	}

	exists, err := s.teamStore.CheckTeamMemberEmailExists(ctx, req.Email)
	if err != nil {
		return domain.TeamMember{}, err
	}
	if exists {
		return domain.TeamMember{}, domain.ErrTeamMemberEmailExists
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcryptCost)
	if err != nil {
		return domain.TeamMember{}, err
	}

	var hireDate *time.Time
	if req.HireDate != "" {
		parsed, err := time.Parse("2006-01-02", req.HireDate)
		if err != nil {
			return domain.TeamMember{}, err
		}
		hireDate = &parsed
	}

	member := domain.TeamMember{
		FirstName:         req.FirstName,
		LastName:          req.LastName,
		Email:             req.Email,
		PhoneNumber:       req.PhoneNumber,
		Password:          hashedPassword,
		TeamRole:          domain.TeamRole(req.TeamRole),
		Department:        req.Department,
		JobTitle:          req.JobTitle,
		EmploymentType:    domain.EmploymentType(req.EmploymentType),
		HireDate:          hireDate,
		ProfilePictureURL: req.ProfilePictureURL,
		Bio:               req.Bio,
		WorkPhone:         req.WorkPhone,
		EmergencyContact:  req.EmergencyContact,
		Status:            domain.TeamMemberStatusActive,
		Permissions:       req.Permissions,
		CreatedBy:         createdBy,
	}

	return s.teamStore.CreateTeamMember(ctx, member)
}

func (s *Service) GetTeamMemberByID(ctx context.Context, id int64) (domain.TeamMember, error) {
	return s.teamStore.GetTeamMemberByID(ctx, id)
}

func (s *Service) GetTeamMemberByEmail(ctx context.Context, email string) (domain.TeamMember, error) {
	return s.teamStore.GetTeamMemberByEmail(ctx, email)
}

func (s *Service) GetAllTeamMembers(ctx context.Context, filter domain.TeamMemberFilter) ([]domain.TeamMember, int64, error) {
	var limit int32 = 10
	var offset int32 = 0

	if filter.PageSize > 0 {
		limit = int32(filter.PageSize)
	}
	if filter.Page > 0 && filter.PageSize > 0 {
		offset = int32((filter.Page - 1) * filter.PageSize)
	}

	return s.teamStore.GetAllTeamMembers(ctx, filter.TeamRole, filter.Department, filter.Status, limit, offset)
}

func (s *Service) SearchTeamMembers(ctx context.Context, search string, teamRole, status *string) ([]domain.TeamMember, error) {
	return s.teamStore.SearchTeamMembers(ctx, search, teamRole, status)
}

func (s *Service) UpdateTeamMember(ctx context.Context, req domain.UpdateTeamMemberReq) error {
	if req.TeamRole != "" && !domain.TeamRole(req.TeamRole).IsValid() {
		return domain.ErrInvalidTeamRole
	}

	if req.EmploymentType != "" && !domain.EmploymentType(req.EmploymentType).IsValid() {
		return domain.ErrInvalidEmploymentType
	}

	return s.teamStore.UpdateTeamMember(ctx, req)
}

func (s *Service) UpdateTeamMemberStatus(ctx context.Context, req domain.UpdateTeamMemberStatusReq) error {
	if !domain.TeamMemberStatus(req.Status).IsValid() {
		return domain.ErrInvalidTeamMemberStatus
	}

	return s.teamStore.UpdateTeamMemberStatus(ctx, req)
}

func (s *Service) DeleteTeamMember(ctx context.Context, memberID int64) error {
	return s.teamStore.DeleteTeamMember(ctx, memberID)
}

func (s *Service) GetTeamMemberStats(ctx context.Context) (domain.TeamMemberStats, error) {
	return s.teamStore.CountTeamMembersByStatus(ctx)
}

func (s *Service) Login(ctx context.Context, req domain.TeamMemberLoginReq) (domain.TeamMember, error) {
	member, err := s.teamStore.GetTeamMemberByEmail(ctx, req.Email)
	if err != nil {
		return domain.TeamMember{}, err
	}

	if err := bcrypt.CompareHashAndPassword(member.Password, []byte(req.Password)); err != nil {
		return domain.TeamMember{}, err
	}

	if err := s.teamStore.UpdateTeamMemberLastLogin(ctx, member.ID); err != nil {
		return domain.TeamMember{}, err
	}

	return member, nil
}

func (s *Service) ChangePassword(ctx context.Context, memberID int64, currentPassword, newPassword string) error {
	member, err := s.teamStore.GetTeamMemberByID(ctx, memberID)
	if err != nil {
		return err
	}

	if err := bcrypt.CompareHashAndPassword(member.Password, []byte(currentPassword)); err != nil {
		return err
	}

	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcryptCost)
	if err != nil {
		return err
	}

	return s.teamStore.UpdateTeamMemberPassword(ctx, memberID, string(hashedPassword))
}

func (s *Service) ResetPassword(ctx context.Context, memberID int64, newPassword string) error {
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcryptCost)
	if err != nil {
		return err
	}

	return s.teamStore.UpdateTeamMemberPassword(ctx, memberID, string(hashedPassword))
}
