package mail

import (
	"context"
	"strings"

	"github.com/jackc/pgx/v5"
)

type reorderLabelItem struct {
	ID        string `json:"id"`
	SortOrder int    `json:"sort_order"`
}

type reorderLabelsRequest struct {
	Items []reorderLabelItem `json:"items"`
}

type reorderUnifiedFolderItem struct {
	ID        string  `json:"id"`
	SortOrder int     `json:"sort_order"`
	ParentID  *string `json:"parent_id"`
}

type reorderUnifiedFoldersRequest struct {
	Items []reorderUnifiedFolderItem `json:"items"`
}

func (s *Service) ReorderUserLabels(ctx context.Context, externalID string, req *reorderLabelsRequest) error {
	if len(req.Items) == 0 {
		return nil
	}
	userID, err := s.ResolveUserID(ctx, externalID)
	if err != nil {
		return err
	}

	tx, err := s.db.Begin(ctx)
	if err != nil {
		return err
	}
	defer tx.Rollback(ctx)

	for _, item := range req.Items {
		id := strings.TrimSpace(item.ID)
		if id == "" {
			continue
		}
		tag, err := tx.Exec(ctx, `
			UPDATE mail_user_labels SET sort_order = $1
			WHERE id = $2 AND user_id = $3
		`, item.SortOrder, id, userID)
		if err != nil {
			return err
		}
		if tag.RowsAffected() == 0 {
			return ErrNotFound
		}
	}
	return tx.Commit(ctx)
}

func (s *Service) ReorderUnifiedFolders(ctx context.Context, externalID string, req *reorderUnifiedFoldersRequest) error {
	if len(req.Items) == 0 {
		return nil
	}
	userID, err := s.ResolveUserID(ctx, externalID)
	if err != nil {
		return err
	}

	tx, err := s.db.Begin(ctx)
	if err != nil {
		return err
	}
	defer tx.Rollback(ctx)

	for _, item := range req.Items {
		id := strings.TrimSpace(item.ID)
		if id == "" {
			continue
		}

		var parentArg any
		if item.ParentID != nil {
			parentID := strings.TrimSpace(*item.ParentID)
			if parentID != "" {
				parentArg = parentID
				var parentAccountID *string
				if err := tx.QueryRow(ctx, `
					SELECT account_id FROM mail_unified_folders WHERE id = $1 AND user_id = $2
				`, parentID, userID).Scan(&parentAccountID); err != nil {
					if err == pgx.ErrNoRows {
						return ErrNotFound
					}
					return err
				}
				var folderAccountID *string
				if err := tx.QueryRow(ctx, `
					SELECT account_id FROM mail_unified_folders WHERE id = $1 AND user_id = $2
				`, id, userID).Scan(&folderAccountID); err != nil {
					if err == pgx.ErrNoRows {
						return ErrNotFound
					}
					return err
				}
				if (folderAccountID == nil) != (parentAccountID == nil) {
					return ErrInvalidFolderScope
				}
				if folderAccountID != nil && parentAccountID != nil && *folderAccountID != *parentAccountID {
					return ErrInvalidFolderScope
				}
			}
		}

		tag, err := tx.Exec(ctx, `
			UPDATE mail_unified_folders SET
				sort_order = $1,
				parent_id = $2,
				updated_at = NOW()
			WHERE id = $3 AND user_id = $4
		`, item.SortOrder, parentArg, id, userID)
		if err != nil {
			return err
		}
		if tag.RowsAffected() == 0 {
			return ErrNotFound
		}
	}
	return tx.Commit(ctx)
}
