CREATE OR REPLACE FUNCTION slugify(input text, table_name text, column_name text) 
RETURNS text AS $$
DECLARE
    base_slug text;
    final_slug text;
    counter integer := 1;
    max_length integer := 15;
    existing_slug text;
BEGIN
    -- Generate the initial base slug
    base_slug := unaccent(input);
    base_slug := lower(base_slug);
    -- Remove single and double quotes
    base_slug := regexp_replace(base_slug, '[''"]+', '', 'gi');
    -- Replace anything that's not a letter, number, hyphen, or underscore with a hyphen
    base_slug := regexp_replace(base_slug, '[^a-z0-9\-_]+', '-', 'gi');
    -- Trim hyphens from the ends
    base_slug := regexp_replace(base_slug, '\-+$', '');
    base_slug := regexp_replace(base_slug, '^\-', '');
    
    -- Truncate the base slug to leave room for the counter
    -- Max length minus 4 characters (for potential "-999" suffix)
    base_slug := substring(base_slug, 1, max_length - 4);
    
    -- Remove any trailing hyphen after truncation
    base_slug := regexp_replace(base_slug, '\-+$', '');
    
    -- Try the base slug first
    final_slug := base_slug;
    
    -- Check if the slug exists using dynamic SQL
    LOOP
        EXECUTE format('SELECT %I FROM %I WHERE %I = $1 LIMIT 1', 
                      column_name, table_name, column_name)
        INTO existing_slug
        USING final_slug;
        
        EXIT WHEN existing_slug IS NULL;
        
        -- If slug exists, append counter and increment
        final_slug := base_slug || '-' || counter;
        counter := counter + 1;
        
        -- Ensure the final slug with counter doesn't exceed max length
        IF length(final_slug) > max_length THEN
            -- Truncate base_slug further to accommodate counter
            base_slug := substring(base_slug, 1, max_length - length(counter::text) - 1);
            final_slug := base_slug || '-' || counter;
        END IF;
    END LOOP;
    
    RETURN final_slug;
END;
$$ LANGUAGE plpgsql STRICT;