package com.storycove.service;

import com.storycove.dto.AuthorSearchDto;
import com.storycove.dto.CollectionDto;
import com.storycove.dto.SearchResultDto;
import com.storycove.dto.StorySearchDto;
import com.storycove.entity.Author;
import com.storycove.entity.Collection;
import com.storycove.entity.Story;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

/**
 * Service adapter that provides a unified interface for search operations.
 *
 * This adapter directly delegates to SolrService.
 */
@Service
public class SearchServiceAdapter {

    private static final Logger logger = LoggerFactory.getLogger(SearchServiceAdapter.class);

    @Autowired
    private SolrService solrService;

    // ===============================
    // SEARCH OPERATIONS
    // ===============================

    /**
     * Search stories with unified interface
     */
    public SearchResultDto<StorySearchDto> searchStories(String query, List<String> tags, String author,
                                                         String series, Integer minWordCount, Integer maxWordCount,
                                                         Float minRating, Boolean isRead, Boolean isFavorite,
                                                         String sortBy, String sortOrder, int page, int size,
                                                         List<String> facetBy,
                                                         // Advanced filters
                                                         String createdAfter, String createdBefore,
                                                         String lastReadAfter, String lastReadBefore,
                                                         Boolean unratedOnly, String readingStatus,
                                                         Boolean hasReadingProgress, Boolean hasCoverImage,
                                                         String sourceDomain, String seriesFilter,
                                                         Integer minTagCount, Boolean popularOnly,
                                                         Boolean hiddenGemsOnly) {
        logger.info("SearchServiceAdapter: delegating search to SolrService");
        try {
            SearchResultDto<StorySearchDto> result = solrService.searchStories(query, tags, author, series, minWordCount, maxWordCount,
                minRating, isRead, isFavorite, sortBy, sortOrder, page, size, facetBy,
                createdAfter, createdBefore, lastReadAfter, lastReadBefore, unratedOnly, readingStatus,
                hasReadingProgress, hasCoverImage, sourceDomain, seriesFilter, minTagCount, popularOnly,
                hiddenGemsOnly);
            logger.info("SearchServiceAdapter: received result with {} stories and {} facets",
                result.getResults().size(), result.getFacets().size());
            return result;
        } catch (Exception e) {
            logger.error("SearchServiceAdapter: error during search", e);
            throw e;
        }
    }

    /**
     * Get random stories with unified interface
     */
    public List<StorySearchDto> getRandomStories(int count, List<String> tags, String author,
                                                String series, Integer minWordCount, Integer maxWordCount,
                                                Float minRating, Boolean isRead, Boolean isFavorite,
                                                Long seed) {
        return solrService.getRandomStories(count, tags, author, series, minWordCount, maxWordCount,
            minRating, isRead, isFavorite, seed);
    }

    /**
     * Recreate search indices
     */
    public void recreateIndices() {
        try {
            solrService.recreateIndices();
        } catch (Exception e) {
            logger.error("Failed to recreate search indices", e);
            throw new RuntimeException("Failed to recreate search indices", e);
        }
    }

    /**
     * Recreates the Solr index schema (drops and re-creates cores / clears all documents).
     *
     * <p><strong>Warning:</strong> This method only clears the index — it does NOT repopulate
     * it with data. Callers are responsible for calling {@link #bulkIndexStories},
     * {@link #bulkIndexAuthors}, and {@link #bulkIndexCollections} afterwards.
     * Use {@code POST /api/admin/search/solr/reindex} for a full reindex including data.</p>
     *
     * @deprecated Prefer the admin endpoint or directly call the bulk-index methods after
     *             fetching data from the repositories.
     */
    @Deprecated
    public void performCompleteReindex() {
        try {
            recreateIndices();
            logger.info("Search indices recreated (schema only — data must be re-added separately)");
        } catch (Exception e) {
            logger.error("Failed to recreate search indices", e);
            throw new RuntimeException("Failed to recreate search indices", e);
        }
    }

    /**
     * Get random story ID with unified interface
     */
    public String getRandomStoryId(Long seed) {
        return solrService.getRandomStoryId(seed);
    }

    /**
     * Search authors with unified interface
     */
    public List<AuthorSearchDto> searchAuthors(String query, int limit) {
        return solrService.searchAuthors(query, limit);
    }

    /**
     * Get tag suggestions with unified interface
     */
    public List<String> getTagSuggestions(String query, int limit) {
        return solrService.getTagSuggestions(query, limit);
    }

    /**
     * Search collections with unified interface
     */
    public SearchResultDto<CollectionDto> searchCollections(String query, List<String> tags,
                                                            boolean includeArchived, int page, int limit) {
        return solrService.searchCollections(query, tags, includeArchived, page, limit);
    }

    // ===============================
    // INDEX OPERATIONS
    // ===============================

    /**
     * Index a story in Solr
     */
    public void indexStory(Story story) {
        try {
            solrService.indexStory(story);
        } catch (Exception e) {
            logger.error("Failed to index story {}", story.getId(), e);
        }
    }

    /**
     * Update a story in Solr
     */
    public void updateStory(Story story) {
        try {
            solrService.updateStory(story);
        } catch (Exception e) {
            logger.error("Failed to update story {}", story.getId(), e);
        }
    }

    /**
     * Delete a story from Solr
     */
    public void deleteStory(UUID storyId) {
        try {
            solrService.deleteStory(storyId);
        } catch (Exception e) {
            logger.error("Failed to delete story {}", storyId, e);
        }
    }

    /**
     * Index an author in Solr
     */
    public void indexAuthor(Author author) {
        try {
            solrService.indexAuthor(author);
        } catch (Exception e) {
            logger.error("Failed to index author {}", author.getId(), e);
        }
    }

    /**
     * Update an author in Solr
     */
    public void updateAuthor(Author author) {
        try {
            solrService.updateAuthor(author);
        } catch (Exception e) {
            logger.error("Failed to update author {}", author.getId(), e);
        }
    }

    /**
     * Delete an author from Solr
     */
    public void deleteAuthor(UUID authorId) {
        try {
            solrService.deleteAuthor(authorId);
        } catch (Exception e) {
            logger.error("Failed to delete author {}", authorId, e);
        }
    }

    /**
     * Bulk index stories in Solr
     */
    public void bulkIndexStories(List<Story> stories) {
        try {
            solrService.bulkIndexStories(stories);
        } catch (Exception e) {
            logger.error("Failed to bulk index {} stories", stories.size(), e);
        }
    }

    /**
     * Bulk index authors in Solr
     */
    public void bulkIndexAuthors(List<Author> authors) {
        try {
            solrService.bulkIndexAuthors(authors);
        } catch (Exception e) {
            logger.error("Failed to bulk index {} authors", authors.size(), e);
        }
    }

    /**
     * Index a collection in Solr
     */
    public void indexCollection(Collection collection) {
        try {
            solrService.indexCollection(collection);
        } catch (Exception e) {
            logger.error("Failed to index collection {}", collection.getId(), e);
        }
    }

    /**
     * Update a collection in Solr
     */
    public void updateCollection(Collection collection) {
        try {
            solrService.updateCollection(collection);
        } catch (Exception e) {
            logger.error("Failed to update collection {}", collection.getId(), e);
        }
    }

    /**
     * Delete a collection from Solr
     */
    public void deleteCollection(UUID collectionId) {
        try {
            solrService.deleteCollection(collectionId);
        } catch (Exception e) {
            logger.error("Failed to delete collection {}", collectionId, e);
        }
    }

    /**
     * Bulk index collections in Solr
     */
    public void bulkIndexCollections(List<Collection> collections) {
        try {
            solrService.bulkIndexCollections(collections);
        } catch (Exception e) {
            logger.error("Failed to bulk index {} collections", collections.size(), e);
        }
    }

    // ===============================
    // UTILITY METHODS
    // ===============================

    /**
     * Check if search service is available and healthy
     */
    public boolean isSearchServiceAvailable() {
        return solrService.testConnection();
    }

    /**
     * Get current search engine name
     */
    public String getCurrentSearchEngine() {
        return "solr";
    }

    /**
     * Check if dual-write is enabled
     */
    public boolean isDualWriteEnabled() {
        return false; // No longer supported
    }

    /**
     * Check if we can switch to Solr
     */
    public boolean canSwitchToSolr() {
        return true; // Already using Solr
    }

    /**
     * Check if we can switch to Typesense
     */
    public boolean canSwitchToTypesense() {
        return false; // Typesense no longer available
    }

    /**
     * Get current search status for admin interface
     */
    public SearchStatus getSearchStatus() {
        return new SearchStatus(
            "solr",
            false, // no dual-write
            false, // no typesense
            solrService.testConnection()
        );
    }

    /**
     * DTO for search status
     */
    public static class SearchStatus {
        private final String primaryEngine;
        private final boolean dualWrite;
        private final boolean typesenseAvailable;
        private final boolean solrAvailable;

        public SearchStatus(String primaryEngine, boolean dualWrite,
                          boolean typesenseAvailable, boolean solrAvailable) {
            this.primaryEngine = primaryEngine;
            this.dualWrite = dualWrite;
            this.typesenseAvailable = typesenseAvailable;
            this.solrAvailable = solrAvailable;
        }

        public String getPrimaryEngine() { return primaryEngine; }
        public boolean isDualWrite() { return dualWrite; }
        public boolean isTypesenseAvailable() { return typesenseAvailable; }
        public boolean isSolrAvailable() { return solrAvailable; }
    }
}