# frozen_string_literal: true

class CitizenLab::Database::SchemaPostprocessor
  attr_accessor :original_schema

  def initialize(original_schema)
    @original_schema = original_schema
  end

  def process
    original_schema.dup.tap do |schema|
      install_extensions!(schema)
    end
  end

  private

  # We have to install DB extensions as a post-processing step because there seems to be
  # no way to configure Rails to dump the exact schema we need with the extensions
  # included.
  #
  # By default, `rake db:schema:dump` does what we need and dumps only the schemas of
  # the search path (as defined in `config/database.yml`). However, when dumping a
  # specific set of schemas, the `pg_dump` call generated by `rake db:schemas:dump`
  # includes the `--schema` flag. This means that no `CREATE EXTENSION` statements will
  # be created in the resulting `structure.sql`. In other words, the extensions will be
  # missing, causing any attempt to load the file to fail. See
  # https://github.com/rails/rails/issues/17157#issuecomment-77390997) for more
  # information.
  #
  # The alternative would be to set `config.active_record.dump_schemas = :all` in
  # `config/application.rb`. This would dump all schemas, including the extensions.
  # However, dumping all schemas is not desirable or a convenient option for us as we
  # use schemas to implement multi-tenancy, and we don't want to pollute the
  # `structure.sql` with all the tenants' schemas.
  def install_extensions!(schema)
    unless schema.gsub!(/^CREATE SCHEMA shared_extensions;$/, CREATE_EXTENSIONS_SQL)
      raise "'CREATE SCHEMA shared_extensions;' not found in schema dump."
    end

    unless schema.gsub!(/^DROP SCHEMA IF EXISTS shared_extensions;$/, DROP_EXTENSIONS_SQL)
      raise "'DROP SCHEMA IF EXISTS shared_extensions;' not found in schema dump."
    end
  end

  CREATE_EXTENSIONS_SQL = <<~SQL.chomp
    CREATE SCHEMA shared_extensions;
    
    
    --
    -- Name: pgcrypto; Type: EXTENSION; Schema: -; Owner: -
    --
    
    CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA shared_extensions;


    --
    -- Name: EXTENSION pgcrypto; Type: COMMENT; Schema: -; Owner: -
    --

    COMMENT ON EXTENSION pgcrypto IS 'cryptographic functions';


    --
    -- Name: pg_trgm; Type: EXTENSION; Schema: -; Owner: -
    --

    CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA shared_extensions;


    --
    -- Name: EXTENSION pg_trgm; Type: COMMENT; Schema: -; Owner: -
    --

    COMMENT ON EXTENSION pg_trgm IS 'text similarity measurement and index searching based on trigrams';
    
    
    --
    -- Name: postgis; Type: EXTENSION; Schema: -; Owner: -
    --
    
    CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA shared_extensions;
    
    
    --
    -- Name: EXTENSION postgis; Type: COMMENT; Schema: -; Owner: -
    --
    
    COMMENT ON EXTENSION postgis IS 'PostGIS geometry and geography spatial types and functions';
    
    
    --
    -- Name: uuid-ossp; Type: EXTENSION; Schema: -; Owner: -
    --
    
    CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA shared_extensions;
    
    
    --
    -- Name: EXTENSION "uuid-ossp"; Type: COMMENT; Schema: -; Owner: -
    --
    
    COMMENT ON EXTENSION "uuid-ossp" IS 'generate universally unique identifiers (UUIDs)';


    --
    -- Name: vector; Type: EXTENSION; Schema: -; Owner: -
    --
    
    CREATE EXTENSION IF NOT EXISTS vector WITH SCHEMA shared_extensions;
    
    
    --
    -- Name: EXTENSION vector; Type: COMMENT; Schema: -; Owner: -
    --
    
    COMMENT ON EXTENSION vector IS 'Open-source vector similarity search for Postgres';
  SQL

  DROP_EXTENSIONS_SQL = <<~SQL.chomp # rubocop:disable Rails/SquishedSQLHeredocs
    DROP EXTENSION IF EXISTS vector;
    DROP EXTENSION IF EXISTS "uuid-ossp";
    DROP EXTENSION IF EXISTS postgis;
    DROP EXTENSION IF EXISTS pg_trgm;
    DROP EXTENSION IF EXISTS pgcrypto;
    DROP SCHEMA IF EXISTS shared_extensions;
  SQL
end
