package persistence

import (
	"encoding/json"
	"fmt"

	"github.com/meilisearch/meilisearch-go"
	"github.com/navidrome/navidrome/conf"
	"github.com/navidrome/navidrome/log"
	"github.com/navidrome/navidrome/model"
)

type MeilisearchService struct {
	client meilisearch.ServiceManager
}

func NewMeilisearchService() *MeilisearchService {
	if !conf.Server.Meilisearch.Enabled {
		return nil
	}
	client := meilisearch.New(conf.Server.Meilisearch.Host, meilisearch.WithAPIKey(conf.Server.Meilisearch.ApiKey))
	return &MeilisearchService{client: client}
}

func (s *MeilisearchService) IndexMediaFile(mf *model.MediaFile) {
	if s == nil {
		return
	}
	s.IndexMediaFiles([]model.MediaFile{*mf})
}

func (s *MeilisearchService) IndexMediaFiles(mfs []model.MediaFile) {
	if s == nil || len(mfs) == 0 {
		return
	}
	docs := make([]map[string]interface{}, len(mfs))
	for i, mf := range mfs {
		docs[i] = map[string]interface{}{
			"id":          mf.ID,
			"title":       mf.Title,
			"artist":      mf.Artist,
			"album":       mf.Album,
			"albumArtist": mf.AlbumArtist,
			"path":        mf.Path,
			"year":        mf.Year,
			"genre":       mf.Genre,
		}
	}
	_, err := s.client.Index("mediafiles").AddDocuments(docs, nil)
	if err != nil {
		log.Error("Error indexing mediafiles", "count", len(mfs), err)
	}
}

func (s *MeilisearchService) DeleteMediaFile(id string) {
	if s == nil {
		return
	}
	_, err := s.client.Index("mediafiles").DeleteDocument(id)
	if err != nil {
		log.Error("Error deleting mediafile from index", "id", id, err)
	}
}

func (s *MeilisearchService) DeleteMediaFiles(ids []string) {
	if s == nil {
		return
	}
	_, err := s.client.Index("mediafiles").DeleteDocuments(ids)
	if err != nil {
		log.Error("Error deleting mediafiles from index", "ids", ids, err)
	}
}

func (s *MeilisearchService) IndexAlbum(album *model.Album) {
	if s == nil {
		return
	}
	s.IndexAlbums([]model.Album{*album})
}

func (s *MeilisearchService) IndexAlbums(albums []model.Album) {
	if s == nil || len(albums) == 0 {
		return
	}
	docs := make([]map[string]interface{}, len(albums))
	for i, album := range albums {
		docs[i] = map[string]interface{}{
			"id":          album.ID,
			"name":        album.Name,
			"artist":      album.AlbumArtist,
			"albumArtist": album.AlbumArtist,
			"year":        album.MinYear,
			"genre":       album.Genre,
		}
	}
	_, err := s.client.Index("albums").AddDocuments(docs, nil)
	if err != nil {
		log.Error("Error indexing albums", "count", len(albums), err)
	}
}

func (s *MeilisearchService) DeleteAlbum(id string) {
	if s == nil {
		return
	}
	_, err := s.client.Index("albums").DeleteDocument(id)
	if err != nil {
		log.Error("Error deleting album from index", "id", id, err)
	}
}

func (s *MeilisearchService) DeleteAlbums(ids []string) {
	if s == nil {
		return
	}
	_, err := s.client.Index("albums").DeleteDocuments(ids)
	if err != nil {
		log.Error("Error deleting albums from index", "ids", ids, err)
	}
}

func (s *MeilisearchService) IndexArtist(artist *model.Artist) {
	if s == nil {
		return
	}
	s.IndexArtists([]model.Artist{*artist})
}

func (s *MeilisearchService) IndexArtists(artists []model.Artist) {
	if s == nil || len(artists) == 0 {
		return
	}
	docs := make([]map[string]interface{}, len(artists))
	for i, artist := range artists {
		docs[i] = map[string]interface{}{
			"id":   artist.ID,
			"name": artist.Name,
		}
	}
	_, err := s.client.Index("artists").AddDocuments(docs, nil)
	if err != nil {
		log.Error("Error indexing artists", "count", len(artists), err)
	}
}

func (s *MeilisearchService) DeleteArtist(id string) {
	if s == nil {
		return
	}
	_, err := s.client.Index("artists").DeleteDocument(id)
	if err != nil {
		log.Error("Error deleting artist from index", "id", id, err)
	}
}

func (s *MeilisearchService) DeleteArtists(ids []string) {
	if s == nil {
		return
	}
	_, err := s.client.Index("artists").DeleteDocuments(ids)
	if err != nil {
		log.Error("Error deleting artists from index", "ids", ids, err)
	}
}

func (s *MeilisearchService) Search(indexName string, query string, offset, limit int) ([]string, error) {
	if s == nil {
		return nil, fmt.Errorf("meilisearch is not enabled")
	}
	searchRes, err := s.client.Index(indexName).Search(query, &meilisearch.SearchRequest{
		Offset: int64(offset),
		Limit:  int64(limit),
	})
	if err != nil {
		return nil, err
	}

	var ids []string
	for _, hit := range searchRes.Hits {
		if id, ok := hit["id"]; ok {
			var idStr string
			if err := json.Unmarshal(id, &idStr); err == nil {
				ids = append(ids, idStr)
			}
		}
	}
	// Handle case where id might be non-string if necessary, though simpler is better for now.
	// Meilisearch returns map[string]interface{}
	return ids, nil
}
