package org

import (
	"net/http"
	"strconv"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/api/dto/converter"
	"github.com/tidbcloud/AgentTeam/internal/store/organization"
)

// UpdatePrimaryTeam handles PATCH /api/v1/orgs/:orgId/members/:memberId/primary-team.
// It updates the primary team assignment for the specified organization member.
func (handler *MemberHandler) UpdatePrimaryTeam(r api.AuthenticatedJSON[dto.OrganizationMemberPrimaryTeamUpdateRequest]) (api.Response, error) {
	orgs, ok := handler.organizationProvider()
	if !ok {
		return api.Response{}, api.NewHTTPError(http.StatusNotFound, "Organization provider not installed")
	}

	organizationID := strings.TrimSpace(r.Gin.Param("orgId"))
	memberID := strings.TrimSpace(r.Gin.Param("memberId"))
	if organizationID == "" || memberID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "Invalid request")
	}

	request := r.Body

	member, err := orgs.SwitchOrganizationMemberPrimaryTeamForUser(r.Context(), r.UserID(), organizationID, memberID, request.TeamID)
	if err != nil {
		return api.Response{}, err
	}
	return api.OK(converter.ToOrgMemberView(member)), nil
}

// UpdateRole handles PATCH /api/v1/orgs/:orgId/members/:memberId/role.
// It updates the role of the specified organization member.
func (handler *MemberHandler) UpdateRole(r api.AuthenticatedJSON[dto.OrganizationMemberRoleUpdateRequest]) (api.Response, error) {
	orgs, ok := handler.organizationProvider()
	if !ok {
		return api.Response{}, api.NewHTTPError(http.StatusNotFound, "Organization provider not installed")
	}

	organizationID := strings.TrimSpace(r.Gin.Param("orgId"))
	memberID := strings.TrimSpace(r.Gin.Param("memberId"))
	if organizationID == "" || memberID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "Invalid request")
	}

	request := r.Body

	member, err := orgs.UpdateOrganizationMemberRoleForUser(r.Context(), r.UserID(), organizationID, memberID, request.Role)
	if err != nil {
		return api.Response{}, err
	}
	return api.OK(converter.ToOrgMemberView(member)), nil
}

// RemovalImpact handles GET /api/v1/orgs/:orgId/members/:memberId/removal-impact.
// It returns the confirmation data and blockers for removing one org member.
func (handler *MemberHandler) RemovalImpact(r api.AuthenticatedRequest) (api.Response, error) {
	orgs, ok := handler.organizationProvider()
	if !ok {
		return api.Response{}, api.NewHTTPError(http.StatusNotFound, "Organization provider not installed")
	}

	organizationID := strings.TrimSpace(r.Gin.Param("orgId"))
	memberID := strings.TrimSpace(r.Gin.Param("memberId"))
	if organizationID == "" || memberID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "Invalid request")
	}

	impact, err := orgs.PreviewOrganizationMemberRemovalImpactForUser(r.Context(), r.UserID(), organizationID, memberID)
	if err != nil {
		return api.Response{}, err
	}
	return api.OK(converter.ToOrgMemberRemovalImpact(impact)), nil
}

// Remove handles DELETE /api/v1/orgs/:orgId/members/:memberId.
// It soft-removes the org member and reconciles organization-derived access.
func (handler *MemberHandler) Remove(r api.AuthenticatedRequest) (api.Response, error) {
	orgs, ok := handler.organizationProvider()
	if !ok {
		return api.Response{}, api.NewHTTPError(http.StatusNotFound, "Organization provider not installed")
	}

	organizationID := strings.TrimSpace(r.Gin.Param("orgId"))
	memberID := strings.TrimSpace(r.Gin.Param("memberId"))
	if organizationID == "" || memberID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "Invalid request")
	}

	result, err := orgs.RemoveOrganizationMemberForUser(r.Context(), r.UserID(), organizationID, memberID)
	if err != nil {
		return api.Response{}, err
	}
	return api.OK(converter.ToOrgMemberRemovalResult(result)), nil
}

// List handles GET /api/v1/orgs/:orgId/members.
// It returns all members in the specified organization, or a bounded page
// when pagination query parameters are present.
func (handler *MemberHandler) List(r api.AuthenticatedRequest) (api.Response, error) {
	orgs, ok := handler.organizationProvider()
	if !ok {
		return api.Response{}, api.NewHTTPError(http.StatusNotFound, "Organization provider not installed")
	}

	organizationID := strings.TrimSpace(r.Gin.Param("orgId"))
	if organizationID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "orgId is required")
	}

	rawLimit := r.Gin.Query("limit")
	rawCursor := r.Gin.Query("cursor")
	rawIncludeWorkspaceAccesses := r.Gin.Query("includeWorkspaceAccesses")
	usesPagedList := strings.TrimSpace(rawLimit) != "" || strings.TrimSpace(rawCursor) != ""
	if usesPagedList {
		limit, err := parseOrganizationMemberListLimit(rawLimit)
		if err != nil {
			return api.Response{}, err
		}
		includeWorkspaceAccesses, err := parseOrganizationMemberIncludeWorkspaceAccesses(rawIncludeWorkspaceAccesses)
		if err != nil {
			return api.Response{}, err
		}
		page, err := orgs.ListOrganizationMembersForUserPage(r.Context(), r.UserID(), organizationID, organization.OrganizationMemberListOptions{
			Limit:                    limit,
			Cursor:                   strings.TrimSpace(rawCursor),
			IncludeWorkspaceAccesses: includeWorkspaceAccesses,
		})
		if err != nil {
			return api.Response{}, err
		}
		return api.OK(converter.ToOrgMemberPageResponse(page)), nil
	}

	members, err := orgs.ListOrganizationMembersForUser(r.Context(), r.UserID(), organizationID)
	if err != nil {
		return api.Response{}, err
	}
	return api.OK(converter.ToOrgMemberViews(members)), nil
}

func parseOrganizationMemberListLimit(rawLimit string) (int, error) {
	trimmed := strings.TrimSpace(rawLimit)
	if trimmed == "" {
		return organization.DefaultOrganizationMemberListLimit, nil
	}
	limit, err := strconv.Atoi(trimmed)
	if err != nil {
		return 0, api.NewHTTPError(http.StatusBadRequest, "limit must be an integer")
	}
	if limit <= 0 {
		return 0, api.NewHTTPError(http.StatusBadRequest, "limit must be a positive integer")
	}
	if limit > organization.MaxOrganizationMemberListLimit {
		return organization.MaxOrganizationMemberListLimit, nil
	}
	return limit, nil
}

func parseOrganizationMemberIncludeWorkspaceAccesses(raw string) (bool, error) {
	trimmed := strings.TrimSpace(raw)
	if trimmed == "" {
		return true, nil
	}
	includeWorkspaceAccesses, err := strconv.ParseBool(trimmed)
	if err != nil {
		return false, api.NewHTTPError(http.StatusBadRequest, "includeWorkspaceAccesses must be a boolean")
	}
	return includeWorkspaceAccesses, nil
}

// Create handles POST /api/v1/orgs/:orgId/members.
// It creates a new member in the specified organization.
func (handler *MemberHandler) Create(r api.AuthenticatedJSON[dto.OrganizationMemberCreateRequest]) (api.Response, error) {
	orgs, ok := handler.organizationProvider()
	if !ok {
		return api.Response{}, api.NewHTTPError(http.StatusNotFound, "Organization provider not installed")
	}

	organizationID := strings.TrimSpace(r.Gin.Param("orgId"))
	if organizationID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "orgId is required")
	}

	request := r.Body
	email, err := normalizeEmail(request.Email)
	if err != nil {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, err.Error())
	}

	member, err := orgs.CreateOrganizationMemberForUser(r.Context(), r.UserID(), organizationID, request.TeamID, email, request.DefaultWorkspaceRole)
	if err != nil {
		return api.Response{}, err
	}
	return api.OK(converter.ToOrgMemberView(member)), nil
}

// ListUnits handles GET /api/v1/orgs/:orgId/members/:memberId/units.
// It returns all organizational units the specified member belongs to.
func (handler *MemberHandler) ListUnits(r api.AuthenticatedRequest) (api.Response, error) {
	orgs, ok := handler.organizationProvider()
	if !ok {
		return api.Response{}, api.NewHTTPError(http.StatusNotFound, "Organization provider not installed")
	}

	organizationID := strings.TrimSpace(r.Gin.Param("orgId"))
	memberID := strings.TrimSpace(r.Gin.Param("memberId"))
	if organizationID == "" || memberID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "Invalid request")
	}

	units, err := orgs.ListOrganizationMemberUnitsForUser(r.Context(), r.UserID(), organizationID, memberID)
	if err != nil {
		return api.Response{}, err
	}
	return api.OK(converter.ToOrgMemberUnitViews(units)), nil
}
