package nextcloud

import (
	"context"
	"fmt"
	"path"
	"strings"
)

// PublicShareBinding maps a public link token to owner storage paths.
type PublicShareBinding struct {
	Token     string
	OwnerID   string
	SharePath string // OCS path, e.g. /Documents/hello.docx or /Documents
	ItemType  string // file | folder
}

func (b *PublicShareBinding) IsSingleFile() bool {
	return strings.EqualFold(strings.TrimSpace(b.ItemType), "file")
}

// ClientSourcePath resolves the logical client path for a shared item.
// Single-file shares expose WebDAV at "/" but editors use /filename.
func (b *PublicShareBinding) ClientSourcePath(clientPath, displayName string) string {
	clientPath = NormalizeClientPath(clientPath)
	if clientPath != "/" {
		return clientPath
	}
	if b != nil && b.IsSingleFile() && b.SharePath != "" {
		return NormalizeClientPath("/" + path.Base(strings.TrimPrefix(b.SharePath, "/")))
	}
	if name := strings.TrimSpace(displayName); name != "" {
		return NormalizeClientPath("/" + name)
	}
	return "/"
}

// OwnerPathForClient maps a client-facing path to the owner's Nextcloud path.
func (b *PublicShareBinding) OwnerPathForClient(clientPath, displayName string) string {
	if b == nil {
		return NormalizeClientPath(clientPath)
	}
	src := b.ClientSourcePath(clientPath, displayName)
	rel := strings.TrimPrefix(src, "/")
	sharePath := NormalizeClientPath(b.SharePath)
	if b.IsSingleFile() {
		dir := path.Dir(strings.TrimPrefix(sharePath, "/"))
		if dir == "." || dir == "" {
			return NormalizeClientPath("/" + rel)
		}
		return NormalizeClientPath(path.Join("/", dir, rel))
	}
	if sharePath == "/" || sharePath == "" {
		return NormalizeClientPath("/" + rel)
	}
	return NormalizeClientPath(path.Join(sharePath, rel))
}

func normalizeOCSSharePath(p string) string {
	p = strings.TrimSpace(p)
	if p == "" {
		return "/"
	}
	if !strings.HasPrefix(p, "/") {
		p = "/" + p
	}
	return NormalizeClientPath(p)
}

// ResolvePublicShareBinding resolves owner + OCS share metadata for a public token.
func (c *Client) ResolvePublicShareBinding(ctx context.Context, token, password string) (*PublicShareBinding, error) {
	token = strings.TrimSpace(token)
	if token == "" {
		return nil, ErrInvalidPublicShare
	}
	ownerID, err := c.getPublicShareOwnerID(ctx, token, password)
	if err != nil {
		return nil, err
	}
	ownerID = strings.TrimSpace(ownerID)
	if ownerID == "" {
		return nil, fmt.Errorf("public share owner not found")
	}

	shares, err := c.ListShares(ctx, ownerID, "")
	if err == nil {
		for _, sh := range shares {
			if strings.TrimSpace(sh.Token) != token {
				continue
			}
			itemType := strings.TrimSpace(sh.ItemType)
			if itemType == "" {
				itemType = "folder"
			}
			return &PublicShareBinding{
				Token:     token,
				OwnerID:   ownerID,
				SharePath: normalizeOCSSharePath(sh.Path),
				ItemType:  itemType,
			}, nil
		}
	}

	view, err := c.GetPublicShare(ctx, token, "/", password)
	if err != nil {
		return nil, fmt.Errorf("public share token not found: %w", err)
	}
	itemType := strings.TrimSpace(view.ItemType)
	if itemType == "" {
		itemType = "folder"
	}
	sharePath := "/"
	if itemType == "file" && strings.TrimSpace(view.Name) != "" {
		sharePath = normalizeOCSSharePath("/" + view.Name)
	}
	return &PublicShareBinding{
		Token:     token,
		OwnerID:   ownerID,
		SharePath: sharePath,
		ItemType:  itemType,
	}, nil
}
