package handler

import (
	"github.com/Paca-AI/api/internal/apierr"
	projectdom "github.com/Paca-AI/api/internal/domain/project"
	"github.com/Paca-AI/api/internal/transport/http/dto"
	"github.com/Paca-AI/api/internal/transport/http/middleware"
	"github.com/Paca-AI/api/internal/transport/http/presenter"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// ListMembers handles GET /projects/:projectId/members.
func (h *ProjectHandler) ListMembers(c *gin.Context) {
	id, err := parseProjectID(c)
	if err != nil {
		presenter.Error(c, err)
		return
	}
	members, err := h.svc.ListMembers(c.Request.Context(), id)
	if err != nil {
		presenter.Error(c, err)
		return
	}
	resp := make([]dto.ProjectMemberResponse, 0, len(members))
	for _, m := range members {
		resp = append(resp, dto.ProjectMemberFromEntity(m))
	}
	presenter.OK(c, resp)
}

// AddMember handles POST /projects/:projectId/members.
func (h *ProjectHandler) AddMember(c *gin.Context) {
	id, err := parseProjectID(c)
	if err != nil {
		presenter.Error(c, err)
		return
	}

	var req dto.AddProjectMemberRequest
	if !middleware.BindJSON(c, &req) {
		return
	}

	m, err := h.svc.AddMember(c.Request.Context(), id, projectdom.AddMemberInput{
		UserID:        req.UserID,
		ProjectRoleID: req.ProjectRoleID,
	})
	if err != nil {
		presenter.Error(c, err)
		return
	}
	presenter.Created(c, dto.ProjectMemberFromEntity(m))
}

// UpdateMemberRole handles PATCH /projects/:projectId/members/:memberId.
func (h *ProjectHandler) UpdateMemberRole(c *gin.Context) {
	projectID, err := parseProjectID(c)
	if err != nil {
		presenter.Error(c, err)
		return
	}
	memberID, err := uuid.Parse(c.Param("memberId"))
	if err != nil {
		presenter.Error(c, apierr.New(apierr.CodeBadRequest, "invalid member id"))
		return
	}

	var req dto.UpdateProjectMemberRoleRequest
	if !middleware.BindJSON(c, &req) {
		return
	}

	m, err := h.svc.UpdateMemberRoleByMemberID(c.Request.Context(), projectID, memberID, projectdom.UpdateMemberRoleInput{
		ProjectRoleID: req.ProjectRoleID,
	})
	if err != nil {
		presenter.Error(c, err)
		return
	}
	presenter.OK(c, dto.ProjectMemberFromEntity(m))
}

// RemoveMember handles DELETE /projects/:projectId/members/:memberId.
func (h *ProjectHandler) RemoveMember(c *gin.Context) {
	projectID, err := parseProjectID(c)
	if err != nil {
		presenter.Error(c, err)
		return
	}
	memberID, err := uuid.Parse(c.Param("memberId"))
	if err != nil {
		presenter.Error(c, apierr.New(apierr.CodeBadRequest, "invalid member id"))
		return
	}
	if err := h.svc.RemoveMemberByMemberID(c.Request.Context(), projectID, memberID); err != nil {
		presenter.Error(c, err)
		return
	}
	presenter.OK(c, gin.H{"message": "member removed"})
}

// GetMyProjectPermissions handles GET /projects/:projectId/members/me/permissions.
// It returns the permission map of the authenticated user's project role.
// Any authenticated project member can call this endpoint regardless of which
// permissions their role grants — the lookup is always scoped to themselves.
func (h *ProjectHandler) GetMyProjectPermissions(c *gin.Context) {
	projectID, err := parseProjectID(c)
	if err != nil {
		presenter.Error(c, err)
		return
	}

	claims := middleware.ClaimsFrom(c)
	if claims == nil {
		presenter.Error(c, apierr.New(apierr.CodeUnauthenticated, "unauthenticated"))
		return
	}

	userID, err := uuid.Parse(claims.Subject)
	if err != nil {
		presenter.Error(c, apierr.New(apierr.CodeBadRequest, "invalid subject claim"))
		return
	}

	// Check if request is from an agent and use agent ID if available
	var agentID *uuid.UUID
	if claims.AgentID != nil {
		if parsedAgentID, parseErr := uuid.Parse(*claims.AgentID); parseErr == nil {
			agentID = &parsedAgentID
		}
	}

	perms, err := h.svc.GetMyProjectPermissions(c.Request.Context(), projectID, userID, agentID)
	if err != nil {
		presenter.Error(c, err)
		return
	}

	presenter.OK(c, gin.H{"permissions": perms})
}
