namespace :multitenant do

  task :test => :environment do
    # ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
    ActiveRecord::Base.establish_connection(:test)
  end

  desc "Loads triggers to test database"
  task 'test:triggers' => ['multitenant:test', 'multitenant:triggers']


    class Trigger
      def initialize(table, trigger)
        @table = table
        @trigger = trigger
        @name = "#{table}_tenant_id"
      end

      def drop
        "DROP TRIGGER IF EXISTS #{@name}"
      end

      def create
        "CREATE TRIGGER #{@name} BEFORE INSERT ON #{@table} FOR EACH ROW #{body}"
      end

      def recreate
        [drop, create]
      end

      protected

      def body
        <<-body
          BEGIN
            DECLARE master_id numeric;
            IF @disable_triggers IS NULL THEN
              IF NEW.tenant_id IS NULL THEN
                SET master_id = #{Account.master.id rescue '(SELECT id FROM accounts WHERE master)'};
                #{@trigger}
              END IF;
            END IF;
          END;
        body
      end
    end

    triggers = []

    triggers << Trigger.new('accounts', %q{
      IF NEW.buyer THEN
        SET NEW.tenant_id = NEW.provider_account_id;
      END IF;
    })

    triggers << Trigger.new('audits', %q{
      IF NEW.provider_id <> master_id THEN
        SET NEW.tenant_id = NEW.provider_id;
      END IF;
     })

    triggers << Trigger.new('alerts', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM accounts WHERE id = NEW.account_id AND NOT master);
    })

    triggers << Trigger.new('api_docs_services', %q{
      IF NEW.account_id <> master_id THEN
        SET NEW.tenant_id = NEW.account_id;
      END IF;
    })

    triggers << Trigger.new('application_keys', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM cinstances WHERE id = NEW.application_id AND tenant_id <> master_id);
    })

    triggers << Trigger.new('billing_strategies', %q{
      IF NEW.account_id <> master_id THEN
        SET NEW.tenant_id = NEW.account_id;
      END IF;
    })


    triggers << Trigger.new('cinstances', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM plans WHERE id = NEW.plan_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('configuration_values', %q{
      IF NEW.configurable_type = 'Account' AND NEW.configurable_id <> master_id THEN
        SET NEW.tenant_id = NEW.configurable_id;
      ELSEIF NEW.configurable_type = 'Service' THEN
        SET NEW.tenant_id = (SELECT tenant_id FROM services WHERE id = NEW.configurable_id AND tenant_id <> master_id);
      END IF;
    })


    triggers << Trigger.new('end_user_plans', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM services WHERE id = NEW.service_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('features', %q{
      IF NEW.featurable_type = 'Account' AND NEW.featurable_id <> master_id THEN
        SET NEW.tenant_id = NEW.featurable_id;
      ELSEIF NEW.featurable_type = 'Service' THEN
        SET NEW.tenant_id = (SELECT tenant_id FROM services WHERE id = NEW.featurable_id AND tenant_id <> master_id);
      END IF;
    })


    triggers << Trigger.new('features_plans', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM features WHERE id = NEW.feature_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('fields_definitions', %q{
      IF NEW.account_id <> master_id THEN
        SET NEW.tenant_id = NEW.account_id;
      END IF;
    })


    triggers << Trigger.new('forums', %q{
      IF NEW.account_id <> master_id THEN
        SET NEW.tenant_id = NEW.account_id;
      END IF;
    })

    triggers << Trigger.new('invitations', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM accounts WHERE id = NEW.account_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('invoices', %q{
      IF NEW.provider_account_id <> master_id THEN
        SET NEW.tenant_id = NEW.provider_account_id;
      END IF;
    })


    triggers << Trigger.new('line_items', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM invoices WHERE id = NEW.invoice_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('mail_dispatch_rules', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM accounts WHERE id = NEW.account_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('message_recipients', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM messages WHERE id = NEW.message_id AND tenant_id <> master_id);
    })

    # FIXME: this one is actually weird, the relation is polymorphic but the type is *always* Account

    triggers << Trigger.new('messages', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM accounts WHERE id = NEW.sender_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('metrics', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM services WHERE id = NEW.service_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('moderatorships', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM forums WHERE id = NEW.forum_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('payment_transactions', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM invoices WHERE id = NEW.invoice_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('plan_metrics', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM plans WHERE id = NEW.plan_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('plans', %q{
      IF NEW.type = 'AccountPlan' AND NEW.issuer_id <> master_id THEN
        SET NEW.tenant_id = NEW.issuer_id;
      ELSEIF NEW.type = 'ApplicationPlan' OR NEW.type = 'ServicePlan' THEN
        SET NEW.tenant_id = (SELECT tenant_id FROM services WHERE id = NEW.issuer_id AND tenant_id <> master_id);
      END IF;
    })


    triggers << Trigger.new('posts', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM forums WHERE id = NEW.forum_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('pricing_rules', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM plans WHERE id = NEW.plan_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('profiles', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM accounts WHERE id = NEW.account_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('referrer_filters', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM cinstances WHERE id = NEW.application_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('services', %q{
      IF NEW.account_id <> master_id THEN
          SET NEW.tenant_id = NEW.account_id;
      END IF;
    })


    triggers << Trigger.new('settings', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM accounts WHERE id = NEW.account_id AND tenant_id <> master_id);
    })

    triggers << Trigger.new('authentication_providers', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM accounts WHERE id = NEW.account_id AND tenant_id <> master_id);
    })

    triggers << Trigger.new('slugs', %q{
      IF NEW.sluggable_type = 'Profile' THEN
        SET NEW.tenant_id = (SELECT tenant_id FROM profiles WHERE id = NEW.sluggable_id AND tenant_id <> master_id);
      ELSEIF NEW.sluggable_type = 'Service' THEN
        SET NEW.tenant_id = (SELECT tenant_id FROM services WHERE id = NEW.sluggable_id AND tenant_id <> master_id);
      END IF;
    })


    triggers << Trigger.new('topic_categories', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM forums WHERE id = NEW.forum_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('topics', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM forums WHERE id = NEW.forum_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('usage_limits', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM metrics WHERE id = NEW.metric_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('user_topics', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM topics WHERE id = NEW.topic_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('users', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM accounts WHERE id = NEW.account_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('web_hooks', %q{
      IF NEW.account_id <> master_id THEN
          SET NEW.tenant_id = NEW.account_id;
      END IF;
    })


    triggers << Trigger.new('categories', %q{
      IF NEW.account_id <> master_id THEN
        SET NEW.tenant_id = NEW.account_id;
      END IF;
     })


    triggers << Trigger.new('category_types', %q{
      IF NEW.account_id <> master_id THEN
        SET NEW.tenant_id = NEW.account_id;
      END IF;
    })


    triggers << Trigger.new('tags', %q{
      IF NEW.account_id <> master_id THEN
        SET NEW.tenant_id = NEW.account_id;
      END IF;
    })


    triggers << Trigger.new('taggings', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM tags WHERE id = NEW.tag_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('legal_terms', %q{
      IF NEW.account_id <> master_id THEN
        SET NEW.tenant_id = NEW.account_id;
      END IF;
    })


    triggers << Trigger.new('legal_term_versions', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM legal_terms WHERE id = NEW.legal_term_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('legal_term_acceptances', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM legal_terms WHERE id = NEW.legal_term_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('legal_term_bindings', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM legal_terms WHERE id = NEW.legal_term_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('member_permissions', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM users WHERE id = NEW.user_id);
    })



    triggers << Trigger.new('cms_sections', %q{
      IF NEW.provider_id <> master_id THEN
        SET NEW.tenant_id = NEW.provider_id;
      END IF;
    })


    triggers << Trigger.new('cms_permissions', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM cms_groups WHERE id = NEW.group_id);
    })


    triggers << Trigger.new('cms_groups', %q{
      IF NEW.provider_id <> master_id THEN
        SET NEW.tenant_id = NEW.provider_id;
      END IF;
    })

    # due to table renaming you might have this older trigger on that table


    triggers << Trigger.new('cms_group_sections', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM cms_groups WHERE id = NEW.group_id);
    })


    triggers << Trigger.new('cms_templates', %q{
      IF (master_id IS NULL OR NEW.provider_id <> master_id) THEN
        SET NEW.tenant_id = NEW.provider_id;
      END IF;
    })


    triggers << Trigger.new('cms_templates_versions', %q{
      IF NEW.provider_id <> master_id THEN
        SET NEW.tenant_id = NEW.provider_id;
      END IF;
    })



    triggers << Trigger.new('cms_files', %q{
      IF NEW.provider_id <> master_id THEN
        SET NEW.tenant_id = NEW.provider_id;
      END IF;
    })


    triggers << Trigger.new('log_entries', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM accounts WHERE id = NEW.provider_id AND NOT master);
    })


    triggers << Trigger.new('cms_redirects', %q{
      IF NEW.provider_id <> master_id THEN
        SET NEW.tenant_id = NEW.provider_id;
      END IF;
    })


    triggers << Trigger.new('proxy_logs', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM accounts WHERE id = NEW.provider_id AND NOT master);
    })


    triggers << Trigger.new('proxies', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM services WHERE id = NEW.service_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('proxy_rules', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM proxies WHERE id = NEW.proxy_id AND tenant_id <> master_id);
    })


    triggers << Trigger.new('service_cubert_infos', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM services WHERE id = NEW.service_id AND tenant_id <> master_id);
    })

    triggers << Trigger.new('provider_constraints', %q{
      SET NEW.tenant_id = NEW.provider_id;
    })

    triggers << Trigger.new('proxy_configs', %q{
      SET NEW.tenant_id = (SELECT tenant_id FROM proxies WHERE id = NEW.proxy_id AND tenant_id <> master_id);
    })

  namespace :triggers do
    task :create => :environment do
      triggers.each do |t|
        ActiveRecord::Base.connection.execute(t.create)
      end
    end

    task :drop => :environment  do
      triggers.each do |t|
        ActiveRecord::Base.connection.execute(t.drop)
      end
    end
  end

  desc 'Recreates the DB triggers (delete+create)'
  task :triggers => :environment do
    puts "Recreating trigger, see log/#{Rails.env}.log"
    triggers.each do |t|
      t.recreate.each do |command|
        ActiveRecord::Base.connection.execute(command)
      end
    end
    puts "Recreated #{triggers.size} triggers"
  end

  desc 'Sets the tenant id on all relevant tables'
  task :set_tenant_id => :environment do

    MASTER_ID = Account.master.id

    Account.update_all "tenant_id = provider_account_id", "NOT provider AND (NOT master OR master IS NULL)"
    Account.update_all "tenant_id = id", "provider"
    Alert.update_all "tenant_id = (SELECT tenant_id FROM accounts WHERE id = alerts.account_id AND tenant_id <> #{MASTER_ID})"
    ApiDocs::Service.update_all "tenant_id = account_id", "account_id <> #{MASTER_ID}"
    ApplicationKey.update_all "tenant_id = (SELECT tenant_id FROM cinstances WHERE id = application_keys.application_id AND tenant_id <> #{MASTER_ID})"
    Finance::BillingStrategy.update_all "tenant_id = account_id", "account_id <> #{MASTER_ID}"
    FieldsDefinition.update_all "tenant_id = account_id", "account_id <> #{MASTER_ID}"
    Forum.update_all "tenant_id = account_id", "account_id <> #{MASTER_ID}"
    Invoice.update_all "tenant_id = provider_account_id", "provider_account_id <> #{MASTER_ID}"
    LineItem.update_all "tenant_id = (SELECT tenant_id FROM invoices WHERE id = line_items.invoice_id AND tenant_id <> #{MASTER_ID})"
    Service.update_all "tenant_id = account_id", "account_id <> #{MASTER_ID}"
    Settings.update_all "tenant_id = (SELECT tenant_id FROM accounts WHERE id = settings.account_id AND tenant_id <> #{MASTER_ID})"
    WebHook.update_all "tenant_id = account_id", "account_id <> #{MASTER_ID}"
    EndUserPlan.update_all "tenant_id = (SELECT tenant_id FROM services WHERE id = end_user_plans.service_id AND tenant_id <> #{MASTER_ID})"
    Invitation.update_all "tenant_id = (SELECT tenant_id FROM accounts WHERE id = invitations.account_id AND tenant_id <> #{MASTER_ID})"
    MailDispatchRule.update_all "tenant_id = (SELECT tenant_id FROM accounts WHERE id = mail_dispatch_rules.account_id AND tenant_id <> #{MASTER_ID})"
    Message.update_all "tenant_id = (SELECT tenant_id FROM accounts WHERE id = messages.sender_id AND tenant_id <> #{MASTER_ID})"
    MessageRecipient.update_all "tenant_id = (SELECT tenant_id FROM messages WHERE id = message_recipients.message_id AND tenant_id <> #{MASTER_ID})"
    Metric.update_all "tenant_id = (SELECT tenant_id FROM services WHERE id = metrics.service_id AND tenant_id <> #{MASTER_ID})"
    PaymentTransaction.update_all "tenant_id = (SELECT tenant_id FROM invoices WHERE id = payment_transactions.invoice_id AND tenant_id <> #{MASTER_ID})"
    Moderatorship.update_all "tenant_id = (SELECT tenant_id FROM forums WHERE id = moderatorships.forum_id AND tenant_id <> #{MASTER_ID})"
    Post.update_all "tenant_id = (SELECT tenant_id FROM forums WHERE id = posts.forum_id AND tenant_id <> #{MASTER_ID})"
    Profile.update_all "tenant_id = (SELECT tenant_id FROM accounts WHERE id = profiles.account_id AND tenant_id <> #{MASTER_ID})"
    ReferrerFilter.update_all "tenant_id = (SELECT tenant_id FROM cinstances WHERE id = referrer_filters.application_id AND tenant_id <> #{MASTER_ID})"
    TopicCategory.update_all "tenant_id = (SELECT tenant_id FROM forums WHERE id = topic_categories.forum_id AND tenant_id <> #{MASTER_ID})"
    Topic.update_all "tenant_id = (SELECT tenant_id FROM forums WHERE id = topics.forum_id AND tenant_id <> #{MASTER_ID})"
    UsageLimit.update_all "tenant_id = (SELECT tenant_id FROM metrics WHERE id = usage_limits.metric_id AND tenant_id <> #{MASTER_ID})"
    UserTopic.update_all "tenant_id = (SELECT tenant_id FROM topics WHERE id = user_topics.topic_id AND tenant_id <> #{MASTER_ID})"
    User.update_all "tenant_id = (SELECT tenant_id FROM accounts WHERE id = users.account_id AND tenant_id <> #{MASTER_ID})"
    Slug.update_all "tenant_id = (SELECT tenant_id FROM profiles WHERE id = slugs.sluggable_id AND tenant_id <> #{MASTER_ID})", "sluggable_type = 'Profile'"
    Slug.update_all "tenant_id = (SELECT tenant_id FROM services WHERE id = slugs.sluggable_id AND tenant_id <> #{MASTER_ID})", "sluggable_type = 'Service'"
    Plan.update_all "tenant_id = issuer_id", "type = 'AccountPlan' AND issuer_id <> #{MASTER_ID}"
    Plan.update_all "tenant_id = (SELECT tenant_id FROM services WHERE id = plans.issuer_id AND tenant_id <> #{MASTER_ID})", "type <> 'AccountPlan'"
    PricingRule.update_all "tenant_id = (SELECT tenant_id FROM plans WHERE id = pricing_rules.plan_id AND tenant_id <> #{MASTER_ID})"
    PlanMetric.update_all "tenant_id = (SELECT tenant_id FROM plans WHERE id = plan_metrics.plan_id AND tenant_id <> #{MASTER_ID})"
    Contract.update_all "tenant_id = (SELECT tenant_id FROM plans WHERE id = cinstances.plan_id AND tenant_id <> #{MASTER_ID})"
    Feature.update_all "tenant_id = featurable_id", "featurable_type = 'Account' AND featurable_id <> #{MASTER_ID}"
    Feature.update_all "tenant_id = (SELECT tenant_id FROM services WHERE id = features.featurable_id AND tenant_id <> #{MASTER_ID})", "featurable_type <> 'Account'"
    Feature.connection.execute "UPDATE features_plans SET tenant_id = (SELECT tenant_id FROM features WHERE id = features_plans.feature_id AND tenant_id <> #{MASTER_ID})"

    ActiveRecord::Base.connection.execute "UPDATE tags SET tenant_id = account_id", "account_id <> #{MASTER_ID}"
    ActiveRecord::Base.connection.execute "UPDATE taggings SET tenant_id = (SELECT tenant_id FROM tags WHERE id = taggings.tag_id AND tenant_id <> #{MASTER_ID})"
    LegalTermAcceptance.update_all "tenant_id = (SELECT tenant_id FROM legal_terms WHERE id = legal_term_acceptances.legal_term_id AND tenant_id <> #{MASTER_ID})"
    LegalTermBinding.update_all "tenant_id = (SELECT tenant_id FROM legal_terms WHERE id = legal_term_bindings.legal_term_id AND tenant_id <> #{MASTER_ID})"
    CMS::Section.update_all "tenant_id = provider_id" , "provider_id <> #{MASTER_ID}"
    CMS::Template.update_all "tenant_id = provider_id" , "provider_id <> #{MASTER_ID}"
    CMS::Template::Version.update_all "tenant_id = provider_id" , "provider_id <> #{MASTER_ID}"
    CMS::File.update_all "tenant_id = provider_id" , "provider_id <> #{MASTER_ID}"
    CMS::Redirect.update_all "tenant_id = provider_id" , "provider_id <> #{MASTER_ID}"
    CMS::Group.update_all "tenant_id = provider_id" , "provider_id <> #{MASTER_ID}"
    CMS::Section.update_all "tenant_id = provider_id" , "provider_id <> #{MASTER_ID}"
    CMS::Permission.update_all "tenant_id = (SELECT tenant_id FROM cms_groups WHERE cms_groups.id = group_id)"
    CMS::GroupSection.update_all "tenant_id = (SELECT tenant_id FROM cms_groups WHERE cms_groups.id = group_id)"
    MemberPermission.update_all  "tenant_id = (SELECT tenant_id FROM users WHERE id = user_id)"
    LogEntry.update_all "tenant_id = provider_id", "provider_id <> #{MASTER_ID}"

    Proxy.update_all "tenant_id = (SELECT tenant_id FROM services WHERE id = proxies.service_id AND tenant_id <> #{MASTER_ID})"
    ProxyRules.update_all "tenant_id = (SELECT tenant_id FROM proxies WHERE id = proxy_rules.proxy_id AND tenant_id <> #{MASTER_ID})"
  end
end

Rake::Task['db:seed'].enhance(['multitenant:triggers'])
