## Class to generate sample data for a chatwoot test @Account.
############################################################
### Usage #####
#
#   # Seed an account with all data types in this class
#   Seeders::AccountSeeder.new(account: Account.find(1)).perform!
#
#
############################################################

class Seeders::AccountSeeder
  def initialize(account:)
    raise 'Account Seeding is not allowed.' unless ENV.fetch('ENABLE_ACCOUNT_SEEDING', !Rails.env.production?)

    @account_data = ActiveSupport::HashWithIndifferentAccess.new(YAML.safe_load(Rails.root.join('lib/seeders/seed_data.yml').read))
    @account = account
  end

  def perform!
    set_up_account
    seed_teams
    seed_custom_roles
    set_up_users
    seed_labels
    seed_canned_responses
    seed_inboxes
    seed_contacts
  end

  def set_up_account
    @account.teams.destroy_all
    @account.conversations.destroy_all
    @account.labels.destroy_all
    @account.inboxes.destroy_all
    @account.contacts.destroy_all
    @account.custom_roles.destroy_all if @account.respond_to?(:custom_roles)
  end

  def seed_teams
    @account_data['teams'].each do |team_name|
      @account.teams.create!(name: team_name)
    end
  end

  def seed_custom_roles
    return unless @account_data['custom_roles'].present? && @account.respond_to?(:custom_roles)

    @account_data['custom_roles'].each do |role_data|
      @account.custom_roles.create!(
        name: role_data['name'],
        description: role_data['description'],
        permissions: role_data['permissions']
      )
    end
  end

  def seed_labels
    @account_data['labels'].each do |label|
      @account.labels.create!(label)
    end
  end

  def set_up_users
    @account_data['users'].each do |user|
      user_record = create_user_record(user)
      create_account_user(user_record, user)
      add_user_to_teams(user: user_record, teams: user['team']) if user['team'].present?
    end
  end

  private

  def create_user_record(user)
    user_record = User.create_with(name: user['name'], password: 'Password1!.').find_or_create_by!(email: user['email'].to_s)
    user_record.skip_confirmation!
    user_record.save!
    Avatar::AvatarFromUrlJob.perform_later(user_record, "https://xsgames.co/randomusers/avatar.php?g=#{user['gender']}")
    user_record
  end

  def create_account_user(user_record, user)
    account_user_attrs = build_account_user_attrs(user)
    AccountUser.create_with(account_user_attrs).find_or_create_by!(account_id: @account.id, user_id: user_record.id)
  end

  def build_account_user_attrs(user)
    attrs = { role: (user['role'] || 'agent') }
    custom_role = find_custom_role(user['custom_role']) if user['custom_role'].present?
    attrs[:custom_role] = custom_role if custom_role
    attrs
  end

  def add_user_to_teams(user:, teams:)
    teams.each do |team|
      team_record = @account.teams.where('name LIKE ?', "%#{team.downcase}%").first if team.present?
      TeamMember.find_or_create_by!(team_id: team_record.id, user_id: user.id) unless team_record.nil?
    end
  end

  def find_custom_role(role_name)
    return nil unless @account.respond_to?(:custom_roles)

    @account.custom_roles.find_by(name: role_name)
  end

  def seed_canned_responses(count: 50)
    count.times do
      @account.canned_responses.create(content: Faker::Quote.fortune_cookie, short_code: Faker::Alphanumeric.alpha(number: 10))
    end
  end

  def seed_contacts
    @account_data['contacts'].each do |contact_data|
      contact = @account.contacts.find_or_initialize_by(email: contact_data['email'])
      if contact.new_record?
        contact.update!(contact_data.slice('name', 'email'))
        Avatar::AvatarFromUrlJob.perform_later(contact, "https://xsgames.co/randomusers/avatar.php?g=#{contact_data['gender']}")
      end
      contact_data['conversations'].each do |conversation_data|
        inbox = @account.inboxes.find_by(channel_type: conversation_data['channel'])
        contact_inbox = inbox.contact_inboxes.create_or_find_by!(contact: contact, source_id: (conversation_data['source_id'] || SecureRandom.hex))
        create_conversation(contact_inbox: contact_inbox, conversation_data: conversation_data)
      end
    end
  end

  def create_conversation(contact_inbox:, conversation_data:)
    assignee = User.from_email(conversation_data['assignee']) if conversation_data['assignee'].present?
    conversation = contact_inbox.conversations.create!(account: contact_inbox.inbox.account, contact: contact_inbox.contact,
                                                       inbox: contact_inbox.inbox, assignee: assignee)
    create_messages(conversation: conversation, messages: conversation_data['messages'])
    conversation.update_labels(conversation_data[:labels]) if conversation_data[:labels].present?
    conversation.update!(priority: conversation_data[:priority]) if conversation_data[:priority].present?
  end

  def create_messages(conversation:, messages:)
    messages.each do |message_data|
      sender = find_message_sender(conversation, message_data)
      conversation.messages.create!(
        message_data.slice('content', 'message_type').merge(
          account: conversation.inbox.account, sender: sender, inbox: conversation.inbox
        )
      )
    end
  end

  def find_message_sender(conversation, message_data)
    if message_data['message_type'] == 'incoming'
      conversation.contact
    elsif message_data['sender'].present?
      User.from_email(message_data['sender'])
    end
  end

  def seed_inboxes
    Seeders::InboxSeeder.new(account: @account, company_data: @account_data[:company]).perform!
  end
end
