package handlers

import (
	"Yimaru-Backend/internal/domain"
	jwtutil "Yimaru-Backend/internal/web_server/jwt"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/gofiber/fiber/v2"
	"go.uber.org/zap"
)

// teamMemberLoginRes represents the response body for team member login
type teamMemberLoginRes struct {
	AccessToken  string `json:"access_token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."`
	RefreshToken string `json:"refresh_token" example:""`
	MemberID     int64  `json:"member_id" example:"1"`
	TeamRole     string `json:"team_role" example:"admin"`
}

// changePasswordReq represents the request body for changing password
type changePasswordReq struct {
	CurrentPassword string `json:"current_password" validate:"required" example:"oldpassword123"`
	NewPassword     string `json:"new_password" validate:"required,min=8" example:"newpassword123"`
}

func mapTeamRoleToRole(teamRole domain.TeamRole) domain.Role {
	switch teamRole {
	case domain.TeamRoleSuperAdmin:
		return domain.RoleSuperAdmin
	case domain.TeamRoleAdmin:
		return domain.RoleAdmin
	case domain.TeamRoleInstructor:
		return domain.RoleInstructor
	case domain.TeamRoleSupportAgent:
		return domain.RoleSupport
	default:
		return domain.RoleAdmin
	}
}

// TeamMemberLogin godoc
// @Summary Login team member
// @Description Authenticate a team member (internal staff) with email and password
// @Tags team
// @Accept json
// @Produce json
// @Param body body domain.TeamMemberLoginReq true "Team member login credentials"
// @Success 200 {object} domain.Response{data=teamMemberLoginRes}
// @Failure 400 {object} domain.ErrorResponse
// @Failure 401 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/team/login [post]
func (h *Handler) TeamMemberLogin(c *fiber.Ctx) error {
	var req domain.TeamMemberLoginReq
	if err := c.BodyParser(&req); err != nil {
		h.mongoLoggerSvc.Info("Failed to parse TeamMemberLogin request",
			zap.Int("status_code", fiber.StatusBadRequest),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to login",
			Error:   "Invalid request body: " + err.Error(),
		})
	}

	if valErrs, ok := h.validator.Validate(c, req); !ok {
		var errMsg string
		for field, msg := range valErrs {
			errMsg += fmt.Sprintf("%s: %s; ", field, msg)
		}
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to login",
			Error:   errMsg,
		})
	}

	loginRes, err := h.teamSvc.Login(c.Context(), req)
	if err != nil {
		switch {
		case errors.Is(err, domain.ErrTeamMemberNotFound):
			h.mongoLoggerSvc.Info("Team member login failed: member not found",
				zap.Int("status_code", fiber.StatusUnauthorized),
				zap.String("email", req.Email),
				zap.Error(err),
				zap.Time("timestamp", time.Now()),
			)
			return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
				Message: "Failed to login",
				Error:   "Invalid credentials",
			})
		case errors.Is(err, domain.ErrInvalidTeamMemberStatus):
			h.mongoLoggerSvc.Info("Team member login failed: account suspended or inactive",
				zap.Int("status_code", fiber.StatusUnauthorized),
				zap.String("email", req.Email),
				zap.Error(err),
				zap.Time("timestamp", time.Now()),
			)
			return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
				Message: "Failed to login",
				Error:   "Account is not active",
			})
		default:
			h.mongoLoggerSvc.Error("Team member login failed",
				zap.Int("status_code", fiber.StatusInternalServerError),
				zap.String("email", req.Email),
				zap.Error(err),
				zap.Time("timestamp", time.Now()),
			)
			return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
				Message: "Failed to login",
				Error:   err.Error(),
			})
		}
	}

	role := mapTeamRoleToRole(loginRes.TeamRole)
	accessToken, err := jwtutil.CreateJwt(
		loginRes.ID,
		role,
		h.jwtConfig.JwtAccessKey,
		h.jwtConfig.JwtAccessExpiry,
	)
	if err != nil {
		h.mongoLoggerSvc.Error("Failed to create access token for team member",
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Int64("member_id", loginRes.ID),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to login",
			Error:   "Failed to generate access token",
		})
	}

	h.mongoLoggerSvc.Info("Team member login successful",
		zap.Int("status_code", fiber.StatusOK),
		zap.Int64("member_id", loginRes.ID),
		zap.String("team_role", string(loginRes.TeamRole)),
		zap.Time("timestamp", time.Now()),
	)

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message: "Login successful",
		Data: teamMemberLoginRes{
			AccessToken:  accessToken,
			RefreshToken: "",
			MemberID:     loginRes.ID,
			TeamRole:     string(loginRes.TeamRole),
		},
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

// CreateTeamMember godoc
// @Summary Create a new team member
// @Description Create a new internal team member (admin only)
// @Tags team
// @Accept json
// @Produce json
// @Security Bearer
// @Param body body domain.CreateTeamMemberReq true "Team member creation payload"
// @Success 201 {object} domain.Response{data=domain.TeamMemberResponse}
// @Failure 400 {object} domain.ErrorResponse
// @Failure 401 {object} domain.ErrorResponse
// @Failure 403 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/team/members [post]
func (h *Handler) CreateTeamMember(c *fiber.Ctx) error {
	var req domain.CreateTeamMemberReq
	if err := c.BodyParser(&req); err != nil {
		h.mongoLoggerSvc.Info("Failed to parse CreateTeamMember request",
			zap.Int("status_code", fiber.StatusBadRequest),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to create team member",
			Error:   "Invalid request body: " + err.Error(),
		})
	}

	if valErrs, ok := h.validator.Validate(c, req); !ok {
		var errMsg string
		for field, msg := range valErrs {
			errMsg += fmt.Sprintf("%s: %s; ", field, msg)
		}
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to create team member",
			Error:   errMsg,
		})
	}

	creatorID, ok := c.Locals("user_id").(int64)
	if !ok {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to create team member",
			Error:   "User ID not found in request context",
		})
	}

	member, err := h.teamSvc.CreateTeamMember(c.Context(), req, &creatorID)
	if err != nil {
		switch {
		case errors.Is(err, domain.ErrTeamMemberEmailExists):
			return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
				Message: "Failed to create team member",
				Error:   "Email already exists",
			})
		case errors.Is(err, domain.ErrInvalidTeamRole):
			return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
				Message: "Failed to create team member",
				Error:   "Invalid team role",
			})
		default:
			h.mongoLoggerSvc.Error("Failed to create team member",
				zap.Int("status_code", fiber.StatusInternalServerError),
				zap.Error(err),
				zap.Time("timestamp", time.Now()),
			)
			return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
				Message: "Failed to create team member",
				Error:   err.Error(),
			})
		}
	}

	h.mongoLoggerSvc.Info("Team member created successfully",
		zap.Int("status_code", fiber.StatusCreated),
		zap.Int64("member_id", member.ID),
		zap.Int64("created_by", creatorID),
		zap.Time("timestamp", time.Now()),
	)

	actorRole := string(c.Locals("role").(domain.Role))
	ip := c.IP()
	ua := c.Get("User-Agent")
	meta, _ := json.Marshal(map[string]interface{}{"email": member.Email, "team_role": string(member.TeamRole)})
	go h.activityLogSvc.RecordAction(context.Background(), &creatorID, &actorRole, domain.ActionTeamMemberCreated, domain.ResourceTeamMember, &member.ID, "Created team member: "+member.Email, meta, &ip, &ua)

	h.sendInAppNotification(member.ID, domain.NOTIFICATION_TYPE_TEAM_MEMBER_CREATED, "Welcome to the Team", "You have been added as a team member.")

	return c.Status(fiber.StatusCreated).JSON(domain.Response{
		Message:    "Team member created successfully",
		Data:       toTeamMemberResponse(&member),
		Success:    true,
		StatusCode: fiber.StatusCreated,
	})
}

// GetTeamMember godoc
// @Summary Get team member by ID
// @Description Retrieve a team member's details by their ID
// @Tags team
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "Team Member ID"
// @Success 200 {object} domain.Response{data=domain.TeamMemberResponse}
// @Failure 400 {object} domain.ErrorResponse
// @Failure 401 {object} domain.ErrorResponse
// @Failure 404 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/team/members/{id} [get]
func (h *Handler) GetTeamMember(c *fiber.Ctx) error {
	memberIDStr := c.Params("id")
	memberID, err := strconv.ParseInt(memberIDStr, 10, 64)
	if err != nil || memberID <= 0 {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid member ID",
			Error:   "Member ID must be a valid positive integer",
		})
	}

	member, err := h.teamSvc.GetTeamMemberByID(c.Context(), memberID)
	if err != nil {
		if errors.Is(err, domain.ErrTeamMemberNotFound) {
			return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{
				Message: "Team member not found",
				Error:   err.Error(),
			})
		}
		h.mongoLoggerSvc.Error("Failed to get team member",
			zap.Int64("member_id", memberID),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to get team member",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Team member retrieved successfully",
		Data:       toTeamMemberResponse(&member),
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

// GetAllTeamMembers godoc
// @Summary List all team members
// @Description Get a paginated list of team members with optional filtering
// @Tags team
// @Accept json
// @Produce json
// @Security Bearer
// @Param team_role query string false "Filter by team role (super_admin, admin, content_manager, support_agent, instructor, finance, hr, analyst)"
// @Param department query string false "Filter by department"
// @Param status query string false "Filter by status (active, inactive, suspended, terminated)"
// @Param search query string false "Search by name, email, or phone number"
// @Param page query int false "Page number (default: 1)"
// @Param page_size query int false "Items per page (default: 10, max: 100)"
// @Success 200 {object} domain.Response{data=[]domain.TeamMemberResponse,metadata=domain.Pagination}
// @Failure 401 {object} domain.ErrorResponse
// @Failure 403 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/team/members [get]
func (h *Handler) GetAllTeamMembers(c *fiber.Ctx) error {
	filter := domain.TeamMemberFilter{}

	if teamRole := c.Query("team_role"); teamRole != "" {
		filter.TeamRole = &teamRole
	}
	if department := c.Query("department"); department != "" {
		filter.Department = &department
	}
	if status := c.Query("status"); status != "" {
		filter.Status = &status
	}
	filter.Search = c.Query("search")

	page, _ := strconv.ParseInt(c.Query("page", "1"), 10, 64)
	if page < 1 {
		page = 1
	}
	filter.Page = page

	pageSize, _ := strconv.ParseInt(c.Query("page_size", "10"), 10, 64)
	if pageSize < 1 || pageSize > 100 {
		pageSize = 10
	}
	filter.PageSize = pageSize

	var members []domain.TeamMember
	var total int64
	var err error

	if filter.Search != "" {
		members, err = h.teamSvc.SearchTeamMembers(c.Context(), filter.Search, filter.TeamRole, filter.Status)
		if err == nil {
			total = int64(len(members))
		}
	} else {
		members, total, err = h.teamSvc.GetAllTeamMembers(c.Context(), filter)
	}

	if err != nil {
		h.mongoLoggerSvc.Error("Failed to get team members",
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to get team members",
			Error:   err.Error(),
		})
	}

	memberResponses := make([]domain.TeamMemberResponse, 0, len(members))
	for i := range members {
		memberResponses = append(memberResponses, toTeamMemberResponse(&members[i]))
	}

	totalPages := int((total + filter.PageSize - 1) / filter.PageSize)

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message: "Team members retrieved successfully",
		Data:    memberResponses,
		Success: true,
		MetaData: domain.Pagination{
			Total:       int(total),
			TotalPages:  totalPages,
			CurrentPage: int(filter.Page),
			Limit:       int(filter.PageSize),
		},
		StatusCode: fiber.StatusOK,
	})
}

// UpdateTeamMember godoc
// @Summary Update team member
// @Description Update an existing team member's details (admin only)
// @Tags team
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "Team Member ID"
// @Param body body domain.UpdateTeamMemberReq true "Team member update payload"
// @Success 200 {object} domain.Response
// @Failure 400 {object} domain.ErrorResponse
// @Failure 401 {object} domain.ErrorResponse
// @Failure 403 {object} domain.ErrorResponse
// @Failure 404 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/team/members/{id} [put]
func (h *Handler) UpdateTeamMember(c *fiber.Ctx) error {
	memberIDStr := c.Params("id")
	memberID, err := strconv.ParseInt(memberIDStr, 10, 64)
	if err != nil || memberID <= 0 {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid member ID",
			Error:   "Member ID must be a valid positive integer",
		})
	}

	var req domain.UpdateTeamMemberReq
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to update team member",
			Error:   "Invalid request body: " + err.Error(),
		})
	}

	updaterID, ok := c.Locals("user_id").(int64)
	if !ok {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to update team member",
			Error:   "User ID not found in request context",
		})
	}

	req.TeamMemberID = memberID
	req.UpdatedBy = updaterID

	if err := h.teamSvc.UpdateTeamMember(c.Context(), req); err != nil {
		switch {
		case errors.Is(err, domain.ErrTeamMemberNotFound):
			return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{
				Message: "Team member not found",
				Error:   err.Error(),
			})
		case errors.Is(err, domain.ErrInvalidTeamRole):
			return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
				Message: "Failed to update team member",
				Error:   "Invalid team role",
			})
		default:
			h.mongoLoggerSvc.Error("Failed to update team member",
				zap.Int64("member_id", memberID),
				zap.Int("status_code", fiber.StatusInternalServerError),
				zap.Error(err),
				zap.Time("timestamp", time.Now()),
			)
			return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
				Message: "Failed to update team member",
				Error:   err.Error(),
			})
		}
	}

	h.mongoLoggerSvc.Info("Team member updated successfully",
		zap.Int64("member_id", memberID),
		zap.Int64("updated_by", updaterID),
		zap.Time("timestamp", time.Now()),
	)

	actorRole := string(c.Locals("role").(domain.Role))
	ip := c.IP()
	ua := c.Get("User-Agent")
	meta, _ := json.Marshal(map[string]interface{}{"member_id": memberID})
	go h.activityLogSvc.RecordAction(context.Background(), &updaterID, &actorRole, domain.ActionTeamMemberUpdated, domain.ResourceTeamMember, &memberID, fmt.Sprintf("Updated team member ID: %d", memberID), meta, &ip, &ua)

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Team member updated successfully",
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

// UpdateTeamMemberStatus godoc
// @Summary Update team member status
// @Description Update a team member's status (active, inactive, suspended, terminated)
// @Tags team
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "Team Member ID"
// @Param body body domain.UpdateTeamMemberStatusReq true "Status update payload"
// @Success 200 {object} domain.Response
// @Failure 400 {object} domain.ErrorResponse
// @Failure 401 {object} domain.ErrorResponse
// @Failure 403 {object} domain.ErrorResponse
// @Failure 404 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/team/members/{id}/status [patch]
func (h *Handler) UpdateTeamMemberStatus(c *fiber.Ctx) error {
	memberIDStr := c.Params("id")
	memberID, err := strconv.ParseInt(memberIDStr, 10, 64)
	if err != nil || memberID <= 0 {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid member ID",
			Error:   "Member ID must be a valid positive integer",
		})
	}

	var req domain.UpdateTeamMemberStatusReq
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to update team member status",
			Error:   "Invalid request body: " + err.Error(),
		})
	}

	if valErrs, ok := h.validator.Validate(c, req); !ok {
		var errMsg string
		for field, msg := range valErrs {
			errMsg += fmt.Sprintf("%s: %s; ", field, msg)
		}
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to update team member status",
			Error:   errMsg,
		})
	}

	updaterID, ok := c.Locals("user_id").(int64)
	if !ok {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to update team member status",
			Error:   "User ID not found in request context",
		})
	}

	req.TeamMemberID = memberID
	req.UpdatedBy = updaterID

	if err := h.teamSvc.UpdateTeamMemberStatus(c.Context(), req); err != nil {
		switch {
		case errors.Is(err, domain.ErrTeamMemberNotFound):
			return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{
				Message: "Team member not found",
				Error:   err.Error(),
			})
		case errors.Is(err, domain.ErrInvalidTeamMemberStatus):
			return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
				Message: "Failed to update team member status",
				Error:   "Invalid status value",
			})
		default:
			h.mongoLoggerSvc.Error("Failed to update team member status",
				zap.Int64("member_id", memberID),
				zap.Int("status_code", fiber.StatusInternalServerError),
				zap.Error(err),
				zap.Time("timestamp", time.Now()),
			)
			return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
				Message: "Failed to update team member status",
				Error:   err.Error(),
			})
		}
	}

	h.mongoLoggerSvc.Info("Team member status updated successfully",
		zap.Int64("member_id", memberID),
		zap.String("new_status", req.Status),
		zap.Int64("updated_by", updaterID),
		zap.Time("timestamp", time.Now()),
	)

	actorRole := string(c.Locals("role").(domain.Role))
	ip := c.IP()
	ua := c.Get("User-Agent")
	meta, _ := json.Marshal(map[string]interface{}{"member_id": memberID, "new_status": req.Status})
	go h.activityLogSvc.RecordAction(context.Background(), &updaterID, &actorRole, domain.ActionTeamMemberUpdated, domain.ResourceTeamMember, &memberID, fmt.Sprintf("Updated team member status ID: %d to %s", memberID, req.Status), meta, &ip, &ua)

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Team member status updated successfully",
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

// DeleteTeamMember godoc
// @Summary Delete team member
// @Description Delete a team member (super admin only)
// @Tags team
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "Team Member ID"
// @Success 200 {object} domain.Response
// @Failure 400 {object} domain.ErrorResponse
// @Failure 401 {object} domain.ErrorResponse
// @Failure 403 {object} domain.ErrorResponse
// @Failure 404 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/team/members/{id} [delete]
func (h *Handler) DeleteTeamMember(c *fiber.Ctx) error {
	memberIDStr := c.Params("id")
	memberID, err := strconv.ParseInt(memberIDStr, 10, 64)
	if err != nil || memberID <= 0 {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid member ID",
			Error:   "Member ID must be a valid positive integer",
		})
	}

	if err := h.teamSvc.DeleteTeamMember(c.Context(), memberID); err != nil {
		if errors.Is(err, domain.ErrTeamMemberNotFound) {
			return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{
				Message: "Team member not found",
				Error:   err.Error(),
			})
		}
		h.mongoLoggerSvc.Error("Failed to delete team member",
			zap.Int64("member_id", memberID),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to delete team member",
			Error:   err.Error(),
		})
	}

	h.mongoLoggerSvc.Info("Team member deleted successfully",
		zap.Int64("member_id", memberID),
		zap.Time("timestamp", time.Now()),
	)

	actorID := c.Locals("user_id").(int64)
	actorRole := string(c.Locals("role").(domain.Role))
	ip := c.IP()
	ua := c.Get("User-Agent")
	meta, _ := json.Marshal(map[string]interface{}{"member_id": memberID})
	go h.activityLogSvc.RecordAction(context.Background(), &actorID, &actorRole, domain.ActionTeamMemberDeleted, domain.ResourceTeamMember, &memberID, fmt.Sprintf("Deleted team member ID: %d", memberID), meta, &ip, &ua)

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Team member deleted successfully",
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

// GetTeamMemberStats godoc
// @Summary Get team member statistics
// @Description Get statistics about team members by status
// @Tags team
// @Accept json
// @Produce json
// @Security Bearer
// @Success 200 {object} domain.Response{data=domain.TeamMemberStats}
// @Failure 401 {object} domain.ErrorResponse
// @Failure 403 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/team/stats [get]
func (h *Handler) GetTeamMemberStats(c *fiber.Ctx) error {
	stats, err := h.teamSvc.GetTeamMemberStats(c.Context())
	if err != nil {
		h.mongoLoggerSvc.Error("Failed to get team member stats",
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to get team member stats",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Team member stats retrieved successfully",
		Data:       stats,
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

// ChangeTeamMemberPassword godoc
// @Summary Change team member password
// @Description Change a team member's password (requires current password)
// @Tags team
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "Team Member ID"
// @Param body body changePasswordReq true "Password change payload"
// @Success 200 {object} domain.Response
// @Failure 400 {object} domain.ErrorResponse
// @Failure 401 {object} domain.ErrorResponse
// @Failure 404 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/team/members/{id}/change-password [post]
func (h *Handler) ChangeTeamMemberPassword(c *fiber.Ctx) error {
	memberIDStr := c.Params("id")
	memberID, err := strconv.ParseInt(memberIDStr, 10, 64)
	if err != nil || memberID <= 0 {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid member ID",
			Error:   "Member ID must be a valid positive integer",
		})
	}

	var req changePasswordReq
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to change password",
			Error:   "Invalid request body: " + err.Error(),
		})
	}

	if valErrs, ok := h.validator.Validate(c, req); !ok {
		var errMsg string
		for field, msg := range valErrs {
			errMsg += fmt.Sprintf("%s: %s; ", field, msg)
		}
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to change password",
			Error:   errMsg,
		})
	}

	if err := h.teamSvc.ChangePassword(c.Context(), memberID, req.CurrentPassword, req.NewPassword); err != nil {
		switch {
		case errors.Is(err, domain.ErrTeamMemberNotFound):
			return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{
				Message: "Team member not found",
				Error:   err.Error(),
			})
		default:
			h.mongoLoggerSvc.Error("Failed to change team member password",
				zap.Int64("member_id", memberID),
				zap.Int("status_code", fiber.StatusInternalServerError),
				zap.Error(err),
				zap.Time("timestamp", time.Now()),
			)
			return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
				Message: "Failed to change password",
				Error:   err.Error(),
			})
		}
	}

	h.mongoLoggerSvc.Info("Team member password changed successfully",
		zap.Int64("member_id", memberID),
		zap.Time("timestamp", time.Now()),
	)

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Password changed successfully",
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

// GetMyTeamProfile godoc
// @Summary Get my team profile
// @Description Get the authenticated team member's own profile
// @Tags team
// @Accept json
// @Produce json
// @Security Bearer
// @Success 200 {object} domain.Response{data=domain.TeamMemberResponse}
// @Failure 400 {object} domain.ErrorResponse
// @Failure 401 {object} domain.ErrorResponse
// @Failure 404 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/team/me [get]
func (h *Handler) GetMyTeamProfile(c *fiber.Ctx) error {
	memberID, ok := c.Locals("user_id").(int64)
	if !ok {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid user context",
			Error:   "User ID not found in request context",
		})
	}

	member, err := h.teamSvc.GetTeamMemberByID(c.Context(), memberID)
	if err != nil {
		if errors.Is(err, domain.ErrTeamMemberNotFound) {
			return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{
				Message: "Team member not found",
				Error:   err.Error(),
			})
		}
		h.mongoLoggerSvc.Error("Failed to get team member profile",
			zap.Int64("member_id", memberID),
			zap.Int("status_code", fiber.StatusInternalServerError),
			zap.Error(err),
			zap.Time("timestamp", time.Now()),
		)
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to get profile",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Profile retrieved successfully",
		Data:       toTeamMemberResponse(&member),
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

func toTeamMemberResponse(m *domain.TeamMember) domain.TeamMemberResponse {
	resp := domain.TeamMemberResponse{
		ID:                m.ID,
		FirstName:         m.FirstName,
		LastName:          m.LastName,
		Email:             m.Email,
		PhoneNumber:       m.PhoneNumber,
		TeamRole:          m.TeamRole,
		Department:        m.Department,
		JobTitle:          m.JobTitle,
		EmploymentType:    m.EmploymentType,
		ProfilePictureURL: m.ProfilePictureURL,
		Bio:               m.Bio,
		WorkPhone:         m.WorkPhone,
		Status:            m.Status,
		EmailVerified:     m.EmailVerified,
		Permissions:       m.Permissions,
		LastLogin:         m.LastLogin,
		CreatedAt:         m.CreatedAt,
		UpdatedAt:         m.UpdatedAt,
	}

	if m.HireDate != nil {
		resp.HireDate = m.HireDate.Format("2006-01-02")
	}

	return resp
}
