/*
 * SearchFilters.vala
 * 
 * Represents search query parameters and filters.
 * Following GNOME HIG naming conventions and Vala/GObject patterns.
 */

/**
 * SearchContentType - Type of content to search for
 */
public enum RSSuper.SearchContentType {
    ARTICLE,
    AUDIO,
    VIDEO
}

/**
 * SearchSortOption - Sorting options for search results
 */
public enum RSSuper.SearchSortOption {
    RELEVANCE,
    DATE_DESC,
    DATE_ASC,
    TITLE_ASC,
    TITLE_DESC,
    FEED_ASC,
    FEED_DESC
}

/**
 * SearchFilters - Represents search filters and query parameters
 */
public struct RSSuper.SearchFilters {
    public string? date_from { get; set; }
    public string? date_to { get; set; }
    public string[] feed_ids { get; set; }
    public string[] authors { get; set; }
    public SearchContentType? content_type { get; set; }
    
    /**
     * Default constructor
     */
    public SearchFilters(string? date_from = null, string? date_to = null,
                         string[]? feed_ids = null, string[]? authors = null,
                         SearchContentType? content_type = null) {
        this.date_from = date_from;
        this.date_to = date_to;
        this.feed_ids = feed_ids;
        this.authors = authors;
        this.content_type = content_type;
    }
    
    /**
     * Get content type as string
     */
    public string? get_content_type_string() {
        if (this.content_type == null) {
            return null;
        }
        switch (this.content_type) {
            case SearchContentType.ARTICLE:
                return "article";
            case SearchContentType.AUDIO:
                return "audio";
            case SearchContentType.VIDEO:
                return "video";
            default:
                return null;
        }
    }
    
    /**
     * Parse content type from string
     */
    public static SearchContentType? content_type_from_string(string? str) {
        if (str == null) {
            return null;
        }
        switch (str) {
            case "article":
                return SearchContentType.ARTICLE;
            case "audio":
                return SearchContentType.AUDIO;
            case "video":
                return SearchContentType.VIDEO;
            default:
                return null;
        }
    }
    
    /**
     * Get sort option as string
     */
    public static string sort_option_to_string(SearchSortOption option) {
        switch (option) {
            case SearchSortOption.RELEVANCE:
                return "relevance";
            case SearchSortOption.DATE_DESC:
                return "date_desc";
            case SearchSortOption.DATE_ASC:
                return "date_asc";
            case SearchSortOption.TITLE_ASC:
                return "title_asc";
            case SearchSortOption.TITLE_DESC:
                return "title_desc";
            case SearchSortOption.FEED_ASC:
                return "feed_asc";
            case SearchSortOption.FEED_DESC:
                return "feed_desc";
            default:
                return "relevance";
        }
    }
    
    /**
     * Parse sort option from string
     */
    public static SearchSortOption sort_option_from_string(string str) {
        switch (str) {
            case "relevance":
                return SearchSortOption.RELEVANCE;
            case "date_desc":
                return SearchSortOption.DATE_DESC;
            case "date_asc":
                return SearchSortOption.DATE_ASC;
            case "title_asc":
                return SearchSortOption.TITLE_ASC;
            case "title_desc":
                return SearchSortOption.TITLE_DESC;
            case "feed_asc":
                return SearchSortOption.FEED_ASC;
            case "feed_desc":
                return SearchSortOption.FEED_DESC;
            default:
                return SearchSortOption.RELEVANCE;
        }
    }
    
    /**
     * Check if any filters are set
     */
    public bool has_filters() {
        return this.date_from != null ||
               this.date_to != null ||
               (this.feed_ids != null && this.feed_ids.length > 0) ||
               (this.authors != null && this.authors.length > 0) ||
               this.content_type != null;
    }
    
    /**
     * Serialize to JSON string
     */
    public string to_json_string() {
        var sb = new StringBuilder();
        sb.append("{");
        
        var first = true;
        if (this.date_from != null) {
            sb.append("\"dateFrom\":\"");
            sb.append(this.date_from);
            sb.append("\"");
            first = false;
        }
        if (this.date_to != null) {
            if (!first) sb.append(",");
            sb.append("\"dateTo\":\"");
            sb.append(this.date_to);
            sb.append("\"");
            first = false;
        }
        if (this.feed_ids != null && this.feed_ids.length > 0) {
            if (!first) sb.append(",");
            sb.append("\"feedIds\":[");
            for (var i = 0; i < this.feed_ids.length; i++) {
                if (i > 0) sb.append(",");
                sb.append("\"");
                sb.append(this.feed_ids[i]);
                sb.append("\"");
            }
            sb.append("]");
            first = false;
        }
        if (this.authors != null && this.authors.length > 0) {
            if (!first) sb.append(",");
            sb.append("\"authors\":[");
            for (var i = 0; i < this.authors.length; i++) {
                if (i > 0) sb.append(",");
                sb.append("\"");
                sb.append(this.authors[i]);
                sb.append("\"");
            }
            sb.append("]");
            first = false;
        }
        if (this.content_type != null) {
            if (!first) sb.append(",");
            sb.append("\"contentType\":\"");
            sb.append(this.get_content_type_string());
            sb.append("\"");
        }
        
        sb.append("}");
        return sb.str;
    }
    
    /**
     * Deserialize from JSON string
     */
    public static SearchFilters? from_json_string(string json_string) {
        var parser = new Json.Parser();
        try {
            if (!parser.load_from_data(json_string)) {
                return null;
            }
        } catch (Error e) {
            warning("Failed to parse JSON: %s", e.message);
            return null;
        }
        
        return from_json_node(parser.get_root());
    }
    
    /**
     * Deserialize from Json.Node
     */
    public static SearchFilters? from_json_node(Json.Node node) {
        if (node.get_node_type() != Json.NodeType.OBJECT) {
            return null;
        }
        
        var obj = node.get_object();
        var filters = SearchFilters();
        
        if (obj.has_member("dateFrom")) {
            filters.date_from = obj.get_string_member("dateFrom");
        }
        if (obj.has_member("dateTo")) {
            filters.date_to = obj.get_string_member("dateTo");
        }
        if (obj.has_member("feedIds")) {
            var array = obj.get_array_member("feedIds");
            var feed_ids = new string[array.get_length()];
            for (var i = 0; i < array.get_length(); i++) {
                feed_ids[i] = array.get_string_element(i);
            }
            filters.feed_ids = feed_ids;
        }
        if (obj.has_member("authors")) {
            var array = obj.get_array_member("authors");
            var authors = new string[array.get_length()];
            for (var i = 0; i < array.get_length(); i++) {
                authors[i] = array.get_string_element(i);
            }
            filters.authors = authors;
        }
        if (obj.has_member("contentType")) {
            filters.content_type = content_type_from_string(obj.get_string_member("contentType"));
        }
        
        return filters;
    }
    
    /**
     * Equality comparison
     */
    public bool equals(SearchFilters other) {
        return this.date_from == other.date_from &&
               this.date_to == other.date_to &&
               this.feeds_equal(other.feed_ids) &&
               this.authors_equal(other.authors) &&
               this.content_type == other.content_type;
    }
    
    /**
     * Helper for feed_ids comparison
     */
    private bool feeds_equal(string[]? other) {
        if (this.feed_ids == null && other == null) return true;
        if (this.feed_ids == null || other == null) return false;
        if (this.feed_ids.length != other.length) {
            return false;
        }
        for (var i = 0; i < this.feed_ids.length; i++) {
            if (this.feed_ids[i] != other[i]) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * Helper for authors comparison
     */
    private bool authors_equal(string[]? other) {
        if (this.authors == null && other == null) return true;
        if (this.authors == null || other == null) return false;
        if (this.authors.length != other.length) {
            return false;
        }
        for (var i = 0; i < this.authors.length; i++) {
            if (this.authors[i] != other[i]) {
                return false;
            }
        }
        return true;
    }
}

/**
 * SearchQuery - Represents a complete search query
 */
public struct RSSuper.SearchQuery {
    public string query { get; set; }
    public int page { get; set; }
    public int page_size { get; set; }
    public string filters_json { get; set; }
    public SearchSortOption sort { get; set; }
    
    /**
     * Default constructor
     */
    public SearchQuery(string query, int page = 1, int page_size = 20,
                       string? filters_json = null, SearchSortOption sort = SearchSortOption.RELEVANCE) {
        this.query = query;
        this.page = page;
        this.page_size = page_size;
        this.filters_json = filters_json;
        this.sort = sort;
    }
    
    /**
     * Get filters as struct
     */
    public SearchFilters? get_filters() {
        if (this.filters_json == null || this.filters_json.length == 0) {
            return null;
        }
        return SearchFilters.from_json_string(this.filters_json);
    }
    
    /**
     * Set filters from struct
     */
    public void set_filters(SearchFilters? filters) {
        if (filters == null) {
            this.filters_json = "";
        } else {
            this.filters_json = filters.to_json_string();
        }
    }
    
    /**
     * Serialize to JSON string
     */
    public string to_json_string() {
        var sb = new StringBuilder();
        sb.append("{");
        sb.append("\"query\":\"");
        sb.append(this.query);
        sb.append("\"");
        sb.append(",\"page\":%d".printf(this.page));
        sb.append(",\"pageSize\":%d".printf(this.page_size));
        if (this.filters_json != null && this.filters_json.length > 0) {
            sb.append(",\"filters\":");
            sb.append(this.filters_json);
        }
        sb.append(",\"sort\":\"");
        sb.append(SearchFilters.sort_option_to_string(this.sort));
        sb.append("\"");
        sb.append("}");
        return sb.str;
    }
    
    /**
     * Deserialize from JSON string
     */
    public static SearchQuery? from_json_string(string json_string) {
        var parser = new Json.Parser();
        try {
            if (!parser.load_from_data(json_string)) {
                return null;
            }
        } catch (Error e) {
            warning("Failed to parse JSON: %s", e.message);
            return null;
        }
        
        return from_json_node(parser.get_root());
    }
    
    /**
     * Deserialize from Json.Node
     */
    public static SearchQuery? from_json_node(Json.Node node) {
        if (node.get_node_type() != Json.NodeType.OBJECT) {
            return null;
        }
        
        var obj = node.get_object();
        
        if (!obj.has_member("query")) {
            return null;
        }
        
        var query = SearchQuery(obj.get_string_member("query"));
        
        if (obj.has_member("page")) {
            query.page = (int)obj.get_int_member("page");
        }
        if (obj.has_member("pageSize")) {
            query.page_size = (int)obj.get_int_member("pageSize");
        }
        if (obj.has_member("filters")) {
            var generator = new Json.Generator();
            generator.set_root(obj.get_member("filters"));
            query.filters_json = generator.to_data(null);
        }
        if (obj.has_member("sort")) {
            query.sort = SearchFilters.sort_option_from_string(obj.get_string_member("sort"));
        }
        
        return query;
    }
    
    /**
     * Equality comparison
     */
    public bool equals(SearchQuery other) {
        return this.query == other.query &&
               this.page == other.page &&
               this.page_size == other.page_size &&
               this.filters_json == other.filters_json &&
               this.sort == other.sort;
    }
}
