class MigrateExistingConversationsToAssistants < ActiveRecord::Migration[7.0]
  # 1. Define stub models inside the migration to make it self-contained
  class Assistant < ApplicationRecord; end
  class AssistantScope < ApplicationRecord; end
  class AssistantConversation < ApplicationRecord; end

  def up
    add_reference :assistant_conversations, :assistant, foreign_key: true, null: true
    AssistantConversation.reset_column_information

    conversations = AssistantConversation.where.not(raggable_id: nil)

    conversations.find_each do |conversation|
      raggable_type = conversation.raggable_type
      raggable_id = conversation.raggable_id

      raggable_class = Object.const_get(raggable_type)
      raggable = raggable_class.find_by(id: raggable_id)

      next unless raggable

      scope = AssistantScope.find_by(scopable_type: raggable_type, scopable_id: raggable_id)

      if scope
        # Fetch using ID instead of association to keep stubs clean
        assistant = Assistant.find(scope.assistant_id)
      else
        assistant_name = raggable.respond_to?(:name) ? raggable.name : "#{raggable_type} Assistant"

        assistant = Assistant.create!(
          name: assistant_name,
          index_name: raggable.index_name.presence || SecureRandom.hex(24)
        )

        AssistantScope.create!(
          assistant_id: assistant.id,
          scopable_type: raggable_type,
          scopable_id: raggable.id
        )
      end

      conversation.update_columns(assistant_id: assistant.id)
    end

    AssistantConversation.where(assistant_id: nil).destroy_all

    remove_index :assistant_conversations, name: "index_assistant_conversations_on_raggable"
    remove_column :assistant_conversations, :raggable_id, :integer
    remove_column :assistant_conversations, :raggable_type, :string

    change_column_null :assistant_conversations, :assistant_id, false
  end

  def down
    add_column :assistant_conversations, :raggable_type, :string
    add_column :assistant_conversations, :raggable_id, :integer
    add_index :assistant_conversations, %i[raggable_id raggable_type], name: "index_assistant_conversations_on_raggable"

    AssistantConversation.reset_column_information

    AssistantConversation.find_each do |conv|
      if conv.assistant_id
        scope = AssistantScope.find_by(assistant_id: conv.assistant_id)
        conv.update_columns(raggable_type: scope.scopable_type, raggable_id: scope.scopable_id) if scope
      end
    end

    remove_reference :assistant_conversations, :assistant, foreign_key: true
  end
end
