// Package client provides a Go SDK for interacting with the MapleFile API.
package client

import (
	"context"
	"fmt"
)

// CreateTag creates a new tag.
func (c *Client) CreateTag(ctx context.Context, input *CreateTagInput) (*Tag, error) {
	var resp Tag
	if err := c.doRequest(ctx, "POST", "/api/v1/tags", input, &resp, true); err != nil {
		return nil, err
	}
	return &resp, nil
}

// ListTags returns all tags for the current user.
func (c *Client) ListTags(ctx context.Context) ([]*Tag, error) {
	var resp ListTagsResponse
	if err := c.doRequest(ctx, "GET", "/api/v1/tags", nil, &resp, true); err != nil {
		return nil, err
	}
	return resp.Tags, nil
}

// GetTag returns a single tag by ID.
func (c *Client) GetTag(ctx context.Context, id string) (*Tag, error) {
	path := fmt.Sprintf("/api/v1/tags/%s", id)
	var resp Tag
	if err := c.doRequest(ctx, "GET", path, nil, &resp, true); err != nil {
		return nil, err
	}
	return &resp, nil
}

// UpdateTag updates a tag.
func (c *Client) UpdateTag(ctx context.Context, id string, input *UpdateTagInput) (*Tag, error) {
	path := fmt.Sprintf("/api/v1/tags/%s", id)
	var resp Tag
	if err := c.doRequest(ctx, "PUT", path, input, &resp, true); err != nil {
		return nil, err
	}
	return &resp, nil
}

// DeleteTag deletes a tag.
func (c *Client) DeleteTag(ctx context.Context, id string) error {
	path := fmt.Sprintf("/api/v1/tags/%s", id)
	return c.doRequest(ctx, "DELETE", path, nil, nil, true)
}

// AssignTag assigns a tag to a collection or file.
func (c *Client) AssignTag(ctx context.Context, input *CreateTagAssignmentInput) (*TagAssignment, error) {
	path := fmt.Sprintf("/api/v1/tags/%s/assign", input.TagID)

	// Create request body without TagID (since it's in the URL)
	requestBody := map[string]string{
		"entity_id":   input.EntityID,
		"entity_type": input.EntityType,
	}

	var resp TagAssignment
	if err := c.doRequest(ctx, "POST", path, requestBody, &resp, true); err != nil {
		return nil, err
	}
	return &resp, nil
}

// UnassignTag removes a tag from a collection or file.
func (c *Client) UnassignTag(ctx context.Context, tagID, entityID, entityType string) error {
	path := fmt.Sprintf("/api/v1/tags/%s/entities/%s?entity_type=%s", tagID, entityID, entityType)
	return c.doRequest(ctx, "DELETE", path, nil, nil, true)
}

// GetTagsForEntity returns all tags assigned to a specific entity (collection or file).
func (c *Client) GetTagsForEntity(ctx context.Context, entityID, entityType string) ([]*Tag, error) {
	path := fmt.Sprintf("/api/v1/tags/%s/%s", entityType, entityID)
	var resp ListTagsResponse
	if err := c.doRequest(ctx, "GET", path, nil, &resp, true); err != nil {
		return nil, err
	}
	return resp.Tags, nil
}

// GetTagAssignments returns all assignments for a specific tag.
func (c *Client) GetTagAssignments(ctx context.Context, tagID string) ([]*TagAssignment, error) {
	path := fmt.Sprintf("/api/v1/tags/%s/assignments", tagID)
	var resp ListTagAssignmentsResponse
	if err := c.doRequest(ctx, "GET", path, nil, &resp, true); err != nil {
		return nil, err
	}
	return resp.TagAssignments, nil
}

// SearchByTags searches for collections and files matching ALL the specified tags.
// tagIDs: slice of tag UUIDs to search for
// limit: maximum number of results (default 50, max 100 on backend)
func (c *Client) SearchByTags(ctx context.Context, tagIDs []string, limit int) (*SearchByTagsResponse, error) {
	if len(tagIDs) == 0 {
		return nil, fmt.Errorf("at least one tag ID is required")
	}

	// Build query string with comma-separated tag IDs
	tags := ""
	for i, id := range tagIDs {
		if i > 0 {
			tags += ","
		}
		tags += id
	}

	path := fmt.Sprintf("/api/v1/tags/search?tags=%s", tags)
	if limit > 0 {
		path += fmt.Sprintf("&limit=%d", limit)
	}

	var resp SearchByTagsResponse
	if err := c.doRequest(ctx, "GET", path, nil, &resp, true); err != nil {
		return nil, err
	}
	return &resp, nil
}
