/*
 * SubscriptionStore.vala
 * 
 * CRUD operations for feed subscriptions.
 */

/**
 * SubscriptionStore - Manages feed subscription persistence
 */
public class RSSuper.SubscriptionStore : Object {
    private Database db;
    
    /**
     * Signal emitted when a subscription is added
     */
    public signal void subscription_added(FeedSubscription subscription);
    
    /**
     * Signal emitted when a subscription is updated
     */
    public signal void subscription_updated(FeedSubscription subscription);
    
    /**
     * Signal emitted when a subscription is deleted
     */
    public signal void subscription_deleted(string id);
    
    /**
     * Create a new subscription store
     */
    public SubscriptionStore(Database db) {
        this.db = db;
    }
    
    /**
     * Add a new subscription
     */
    public FeedSubscription add(FeedSubscription subscription) throws Error {
        var stmt = db.prepare(
            "INSERT INTO feed_subscriptions (id, url, title, category, enabled, fetch_interval, " +
            "created_at, updated_at, last_fetched_at, next_fetch_at, error, http_auth_username, http_auth_password) " +
            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
        );
        
        stmt.bind_text(1, subscription.id, -1, null);
        stmt.bind_text(2, subscription.url, -1, null);
        stmt.bind_text(3, subscription.title, -1, null);
        stmt.bind_text(4, subscription.category ?? "", -1, null);
        stmt.bind_int(5, subscription.enabled ? 1 : 0);
        stmt.bind_int(6, subscription.fetch_interval);
        stmt.bind_text(7, subscription.created_at, -1, null);
        stmt.bind_text(8, subscription.updated_at, -1, null);
        stmt.bind_text(9, subscription.last_fetched_at ?? "", -1, null);
        stmt.bind_text(10, subscription.next_fetch_at ?? "", -1, null);
        stmt.bind_text(11, subscription.error ?? "", -1, null);
        stmt.bind_text(12, subscription.http_auth_username ?? "", -1, null);
        stmt.bind_text(13, subscription.http_auth_password ?? "", -1, null);
        
        stmt.step();
        
        debug("Subscription added: %s", subscription.id);
        subscription_added(subscription);
        
        return subscription;
    }
    
    /**
     * Get a subscription by ID
     */
    public FeedSubscription? get_by_id(string id) throws Error {
        var stmt = db.prepare(
            "SELECT id, url, title, category, enabled, fetch_interval, created_at, updated_at, " +
            "last_fetched_at, next_fetch_at, error, http_auth_username, http_auth_password " +
            "FROM feed_subscriptions WHERE id = ?;"
        );
        
        stmt.bind_text(1, id, -1, null);
        
        if (stmt.step() == Sqlite.ROW) {
            return row_to_subscription(stmt);
        }
        
        return null;
    }
    
    /**
     * Get all subscriptions
     */
    public FeedSubscription[] get_all() throws Error {
        var subscriptions = new GLib.List<FeedSubscription?>();
        
        var stmt = db.prepare(
            "SELECT id, url, title, category, enabled, fetch_interval, created_at, updated_at, " +
            "last_fetched_at, next_fetch_at, error, http_auth_username, http_auth_password " +
            "FROM feed_subscriptions ORDER BY title;"
        );
        
        while (stmt.step() == Sqlite.ROW) {
            var subscription = row_to_subscription(stmt);
            if (subscription != null) {
                subscriptions.append(subscription);
            }
        }
        
        return list_to_array(subscriptions);
    }
    
    /**
     * Update a subscription
     */
    public void update(FeedSubscription subscription) throws Error {
        var stmt = db.prepare(
            "UPDATE feed_subscriptions SET url = ?, title = ?, category = ?, enabled = ?, " +
            "fetch_interval = ?, updated_at = ?, last_fetched_at = ?, next_fetch_at = ?, " +
            "error = ?, http_auth_username = ?, http_auth_password = ? " +
            "WHERE id = ?;"
        );
        
        stmt.bind_text(1, subscription.url, -1, null);
        stmt.bind_text(2, subscription.title, -1, null);
        stmt.bind_text(3, subscription.category ?? "", -1, null);
        stmt.bind_int(4, subscription.enabled ? 1 : 0);
        stmt.bind_int(5, subscription.fetch_interval);
        stmt.bind_text(6, subscription.updated_at, -1, null);
        stmt.bind_text(7, subscription.last_fetched_at ?? "", -1, null);
        stmt.bind_text(8, subscription.next_fetch_at ?? "", -1, null);
        stmt.bind_text(9, subscription.error ?? "", -1, null);
        stmt.bind_text(10, subscription.http_auth_username ?? "", -1, null);
        stmt.bind_text(11, subscription.http_auth_password ?? "", -1, null);
        stmt.bind_text(12, subscription.id, -1, null);
        
        stmt.step();
        
        debug("Subscription updated: %s", subscription.id);
        subscription_updated(subscription);
    }
    
    /**
     * Delete a subscription
     */
    public void remove_subscription(string id) throws Error {
        var stmt = db.prepare("DELETE FROM feed_subscriptions WHERE id = ?;");
        stmt.bind_text(1, id, -1, null);
        stmt.step();
        
        debug("Subscription deleted: %s", id);
        subscription_deleted(id);
    }
    
    /**
     * Delete a subscription by object
     */
    public void delete_subscription(FeedSubscription subscription) throws Error {
        remove_subscription(subscription.id);
    }
    
    /**
     * Get enabled subscriptions
     */
    public FeedSubscription[] get_enabled() throws Error {
        var subscriptions = new GLib.List<FeedSubscription?>();
        
        var stmt = db.prepare(
            "SELECT id, url, title, category, enabled, fetch_interval, created_at, updated_at, " +
            "last_fetched_at, next_fetch_at, error, http_auth_username, http_auth_password " +
            "FROM feed_subscriptions WHERE enabled = 1 ORDER BY title;"
        );
        
        while (stmt.step() == Sqlite.ROW) {
            var subscription = row_to_subscription(stmt);
            if (subscription != null) {
                subscriptions.append(subscription);
            }
        }
        
        return list_to_array(subscriptions);
    }
    
    /**
     * Get subscriptions that need fetching
     */
    public FeedSubscription[] get_due_for_fetch() throws Error {
        var subscriptions = new GLib.List<FeedSubscription?>();
        var now = new DateTime.now_local();
        var now_str = now.format("%Y-%m-%dT%H:%M:%S");
        
        var stmt = db.prepare(
            "SELECT id, url, title, category, enabled, fetch_interval, created_at, updated_at, " +
            "last_fetched_at, next_fetch_at, error, http_auth_username, http_auth_password " +
            "FROM feed_subscriptions WHERE enabled = 1 AND " +
            "(next_fetch_at IS NULL OR next_fetch_at <= ?) " +
            "ORDER BY next_fetch_at ASC;"
        );
        
        stmt.bind_text(1, now_str, -1, null);
        
        while (stmt.step() == Sqlite.ROW) {
            var subscription = row_to_subscription(stmt);
            if (subscription != null) {
                subscriptions.append(subscription);
            }
        }
        
        return list_to_array(subscriptions);
    }
    
    /**
     * Convert a database row to a FeedSubscription
     */
    private FeedSubscription? row_to_subscription(Sqlite.Statement stmt) {
        try {
            var subscription = new FeedSubscription.with_values(
                stmt.column_text(0),  // id
                stmt.column_text(1),  // url
                stmt.column_text(2),  // title
                stmt.column_int(5),   // fetch_interval
                stmt.column_text(3),  // category
                stmt.column_int(4) == 1,  // enabled
                stmt.column_text(6),  // created_at
                stmt.column_text(7),  // updated_at
                stmt.column_text(8),  // last_fetched_at
                stmt.column_text(9),  // next_fetch_at
                stmt.column_text(10), // error
                stmt.column_text(11), // http_auth_username
                stmt.column_text(12)  // http_auth_password
            );
            
            return subscription;
        } catch (Error e) {
            warning("Failed to parse subscription row: %s", e.message);
            return null;
        }
    }

    private FeedSubscription[] list_to_array(GLib.List<FeedSubscription?> list) {
        FeedSubscription[] arr = {};
        for (unowned var node = list; node != null; node = node.next) {
            if (node.data != null) arr += node.data;
        }
        return arr;
    }

}

