// File Path: monorepo/cloud/maplepress-backend/pkg/search/index.go
package search

import (
	"fmt"

	"github.com/meilisearch/meilisearch-go"
)

// PageDocument represents a document in the search index
type PageDocument struct {
	ID          string `json:"id"`        // page_id
	SiteID      string `json:"site_id"`   // for filtering (though each site has its own index)
	TenantID    string `json:"tenant_id"` // for additional isolation
	Title       string `json:"title"`
	Content     string `json:"content"` // HTML stripped
	Excerpt     string `json:"excerpt"`
	URL         string `json:"url"`
	Status      string `json:"status"`    // publish, draft, trash
	PostType    string `json:"post_type"` // page, post
	Author      string `json:"author"`
	PublishedAt int64  `json:"published_at"` // Unix timestamp for sorting
	ModifiedAt  int64  `json:"modified_at"`  // Unix timestamp for sorting
}

// CreateIndex creates a new index for a site
func (c *Client) CreateIndex(siteID string) error {
	indexName := c.GetIndexName(siteID)

	// Create index with site_id as primary key
	_, err := c.client.CreateIndex(&meilisearch.IndexConfig{
		Uid:        indexName,
		PrimaryKey: "id", // page_id is the primary key
	})

	if err != nil {
		return fmt.Errorf("failed to create index %s: %w", indexName, err)
	}

	// Configure index settings
	return c.ConfigureIndex(siteID)
}

// ConfigureIndex configures the index settings
func (c *Client) ConfigureIndex(siteID string) error {
	indexName := c.GetIndexName(siteID)
	index := c.client.Index(indexName)

	// Set searchable attributes (in order of priority)
	searchableAttributes := []string{
		"title",
		"excerpt",
		"content",
	}

	_, err := index.UpdateSearchableAttributes(&searchableAttributes)
	if err != nil {
		return fmt.Errorf("failed to set searchable attributes: %w", err)
	}

	// Set filterable attributes
	filterableAttributes := []interface{}{
		"status",
		"post_type",
		"author",
		"published_at",
	}

	_, err = index.UpdateFilterableAttributes(&filterableAttributes)
	if err != nil {
		return fmt.Errorf("failed to set filterable attributes: %w", err)
	}

	// Set ranking rules
	rankingRules := []string{
		"words",
		"typo",
		"proximity",
		"attribute",
		"sort",
		"exactness",
	}

	_, err = index.UpdateRankingRules(&rankingRules)
	if err != nil {
		return fmt.Errorf("failed to set ranking rules: %w", err)
	}

	// Set displayed attributes (don't return full content in search results)
	displayedAttributes := []string{
		"id",
		"title",
		"excerpt",
		"url",
		"status",
		"post_type",
		"author",
		"published_at",
		"modified_at",
	}

	_, err = index.UpdateDisplayedAttributes(&displayedAttributes)
	if err != nil {
		return fmt.Errorf("failed to set displayed attributes: %w", err)
	}

	return nil
}

// IndexExists checks if an index exists
func (c *Client) IndexExists(siteID string) (bool, error) {
	indexName := c.GetIndexName(siteID)

	_, err := c.client.GetIndex(indexName)
	if err != nil {
		// Check if error is "index not found" (status code 404)
		if meiliErr, ok := err.(*meilisearch.Error); ok {
			if meiliErr.StatusCode == 404 {
				return false, nil
			}
		}
		return false, fmt.Errorf("failed to check index existence: %w", err)
	}

	return true, nil
}

// DeleteIndex deletes an index for a site
func (c *Client) DeleteIndex(siteID string) error {
	indexName := c.GetIndexName(siteID)

	_, err := c.client.DeleteIndex(indexName)
	if err != nil {
		return fmt.Errorf("failed to delete index %s: %w", indexName, err)
	}

	return nil
}

// AddDocuments adds or updates documents in the index
func (c *Client) AddDocuments(siteID string, documents []PageDocument) (*meilisearch.TaskInfo, error) {
	indexName := c.GetIndexName(siteID)
	index := c.client.Index(indexName)

	taskInfo, err := index.AddDocuments(documents, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to add documents to index %s: %w", indexName, err)
	}

	return taskInfo, nil
}

// UpdateDocuments updates documents in the index
func (c *Client) UpdateDocuments(siteID string, documents []PageDocument) (*meilisearch.TaskInfo, error) {
	indexName := c.GetIndexName(siteID)
	index := c.client.Index(indexName)

	taskInfo, err := index.UpdateDocuments(documents, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to update documents in index %s: %w", indexName, err)
	}

	return taskInfo, nil
}

// DeleteDocument deletes a single document from the index
func (c *Client) DeleteDocument(siteID string, documentID string) (*meilisearch.TaskInfo, error) {
	indexName := c.GetIndexName(siteID)
	index := c.client.Index(indexName)

	taskInfo, err := index.DeleteDocument(documentID)
	if err != nil {
		return nil, fmt.Errorf("failed to delete document %s from index %s: %w", documentID, indexName, err)
	}

	return taskInfo, nil
}

// DeleteDocuments deletes multiple documents from the index
func (c *Client) DeleteDocuments(siteID string, documentIDs []string) (*meilisearch.TaskInfo, error) {
	indexName := c.GetIndexName(siteID)
	index := c.client.Index(indexName)

	taskInfo, err := index.DeleteDocuments(documentIDs)
	if err != nil {
		return nil, fmt.Errorf("failed to delete documents from index %s: %w", indexName, err)
	}

	return taskInfo, nil
}

// DeleteAllDocuments deletes all documents from the index
func (c *Client) DeleteAllDocuments(siteID string) (*meilisearch.TaskInfo, error) {
	indexName := c.GetIndexName(siteID)
	index := c.client.Index(indexName)

	taskInfo, err := index.DeleteAllDocuments()
	if err != nil {
		return nil, fmt.Errorf("failed to delete all documents from index %s: %w", indexName, err)
	}

	return taskInfo, nil
}

// GetStats returns statistics about an index
func (c *Client) GetStats(siteID string) (*meilisearch.StatsIndex, error) {
	indexName := c.GetIndexName(siteID)
	index := c.client.Index(indexName)

	stats, err := index.GetStats()
	if err != nil {
		return nil, fmt.Errorf("failed to get stats for index %s: %w", indexName, err)
	}

	return stats, nil
}
