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

import (
	"context"
	"fmt"
)

// CreateCollection creates a new collection.
func (c *Client) CreateCollection(ctx context.Context, input *CreateCollectionInput) (*Collection, error) {
	var resp Collection
	if err := c.doRequest(ctx, "POST", "/api/v1/collections", input, &resp, true); err != nil {
		return nil, err
	}
	return &resp, nil
}

// ListCollections returns all collections for the current user.
func (c *Client) ListCollections(ctx context.Context) ([]*Collection, error) {
	var resp struct {
		Collections []*Collection `json:"collections"`
	}
	if err := c.doRequest(ctx, "GET", "/api/v1/collections", nil, &resp, true); err != nil {
		return nil, err
	}
	return resp.Collections, nil
}

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

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

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

// GetRootCollections returns all root-level collections (no parent).
func (c *Client) GetRootCollections(ctx context.Context) ([]*Collection, error) {
	var resp struct {
		Collections []*Collection `json:"collections"`
	}
	if err := c.doRequest(ctx, "GET", "/api/v1/collections/root", nil, &resp, true); err != nil {
		return nil, err
	}
	return resp.Collections, nil
}

// GetCollectionsByParent returns all collections with the specified parent.
func (c *Client) GetCollectionsByParent(ctx context.Context, parentID string) ([]*Collection, error) {
	path := fmt.Sprintf("/api/v1/collections/parent/%s", parentID)
	var resp struct {
		Collections []*Collection `json:"collections"`
	}
	if err := c.doRequest(ctx, "GET", path, nil, &resp, true); err != nil {
		return nil, err
	}
	return resp.Collections, nil
}

// MoveCollection moves a collection to a new parent.
func (c *Client) MoveCollection(ctx context.Context, id string, input *MoveCollectionInput) (*Collection, error) {
	path := fmt.Sprintf("/api/v1/collections/%s/move", id)
	var resp Collection
	if err := c.doRequest(ctx, "PUT", path, input, &resp, true); err != nil {
		return nil, err
	}
	return &resp, nil
}

// ShareCollection shares a collection with another user.
func (c *Client) ShareCollection(ctx context.Context, id string, input *ShareCollectionInput) error {
	path := fmt.Sprintf("/api/v1/collections/%s/share", id)
	return c.doRequest(ctx, "POST", path, input, nil, true)
}

// RemoveCollectionMember removes a user from a shared collection.
func (c *Client) RemoveCollectionMember(ctx context.Context, collectionID, userID string) error {
	path := fmt.Sprintf("/api/v1/collections/%s/members/%s", collectionID, userID)
	return c.doRequest(ctx, "DELETE", path, nil, nil, true)
}

// ListSharedCollections returns all collections shared with the current user.
func (c *Client) ListSharedCollections(ctx context.Context) ([]*Collection, error) {
	var resp struct {
		Collections []*Collection `json:"collections"`
	}
	if err := c.doRequest(ctx, "GET", "/api/v1/collections/shared", nil, &resp, true); err != nil {
		return nil, err
	}
	return resp.Collections, nil
}

// ArchiveCollection archives a collection.
func (c *Client) ArchiveCollection(ctx context.Context, id string) (*Collection, error) {
	path := fmt.Sprintf("/api/v1/collections/%s/archive", id)
	var resp Collection
	if err := c.doRequest(ctx, "PUT", path, nil, &resp, true); err != nil {
		return nil, err
	}
	return &resp, nil
}

// RestoreCollection restores an archived collection.
func (c *Client) RestoreCollection(ctx context.Context, id string) (*Collection, error) {
	path := fmt.Sprintf("/api/v1/collections/%s/restore", id)
	var resp Collection
	if err := c.doRequest(ctx, "PUT", path, nil, &resp, true); err != nil {
		return nil, err
	}
	return &resp, nil
}

// GetFilteredCollections returns collections matching the specified filter.
func (c *Client) GetFilteredCollections(ctx context.Context, filter *CollectionFilter) ([]*Collection, error) {
	path := "/api/v1/collections/filtered"
	if filter != nil {
		params := ""
		if filter.State != "" {
			params += fmt.Sprintf("state=%s", filter.State)
		}
		if filter.ParentID != "" {
			if params != "" {
				params += "&"
			}
			params += fmt.Sprintf("parent_id=%s", filter.ParentID)
		}
		if params != "" {
			path += "?" + params
		}
	}
	var resp struct {
		Collections []*Collection `json:"collections"`
	}
	if err := c.doRequest(ctx, "GET", path, nil, &resp, true); err != nil {
		return nil, err
	}
	return resp.Collections, nil
}

// SyncCollections fetches collection changes since the given cursor.
func (c *Client) SyncCollections(ctx context.Context, input *SyncInput) (*CollectionSyncResponse, error) {
	var resp CollectionSyncResponse
	if err := c.doRequest(ctx, "POST", "/api/v1/collections/sync", input, &resp, true); err != nil {
		return nil, err
	}
	return &resp, nil
}
