namespace :multitenant do

  # this is a hash that maps provider ids to the multiplier that was used
  # if provider id is not present, multiplier is id / 16
  MULTIPLIERS = {}

  desc 'runs all BCMS multitenant tasks: i.e. bcms resources link to the first provider in the db'
  task :bcms => ["multitenant:redirects",
                 "multitenant:html_blocks",
                 "multitenant:file_blocks", "multitenant:file_attachments",
                 "multitenant:image_blocks",
                 "multitenant:portlets",
                 "multitenant:tags", "multitenant:category_types", "multitenant:categories",
                 "multitenant:blogs", "multitenant:blog_posts",
                 "multitenant:dynamic_views",
                 "multitenant:groups",
                 "multitenant:links",
                 "multitenant:pages",
                 "multitenant:fix_pages",
                 "multitenant:sections",
                 "multitenant:legal_term_acceptances"]

  desc 'moves every object in the bucket on yml to a directory scoped by s3_provider_prefix'
  task :s3 => :environment do
    # get bucket
    bucket= "s3://#{CMS::S3.options[:bucket]}/"
    provider = if ENV["PROVIDER_ID"]
      Account.providers.find_by_id ENV["PROVIDER_ID"]
               else
      Account.providers.first
               end
    provider_prefix = provider.s3_provider_prefix

    print "You will be migrating all non-prefixed s3 assets to the following prefix: #{provider_prefix}.\nEnter to proceed, CTRL+C to abort."
    STDIN.gets

    prefixes_to_exclude = ([Account.master] + Account.providers).map{|p| "#{bucket}#{p.s3_provider_prefix}/"}

    # move everything in that bucket to
    files_to_move = `s3cmd ls #{bucket}`
    full_paths_of_files_to_move = files_to_move.map{|line| line.split(/\s+/).last}.reject{|line| puts line; prefixes_to_exclude.include?(line)}

    # scoped dir in same bucket
    maps = full_paths_of_files_to_move.map{|file| [file, file.gsub(/#{bucket}/, "#{bucket}#{provider_prefix}/")] }
    puts maps.inspect

    # FIXME: change echo cp to mv
    maps.each do |file|
      system "echo s3cmd cp -r #{file.first} #{file.last}"
      system "s3cmd cp -r #{file.first} #{file.last}"
    end

    FileAttachment.update_all "file_location = concat('#{provider_prefix}/',file_location)", "account_id = #{provider.id}"
    FileAttachment::Version.update_all "file_location = concat('#{provider_prefix}/',file_location)", "account_id = #{provider.id}"

    puts "~ All Assets in amazon s3 are now in the subdir #{bucket}#{provider_prefix}/"
  end

  desc 'removes the non prefixed s3 assets, make sure you run multitenant:s3 before'
  task :remove_non_prefixed_s3_assets => :environment do
    bucket= "s3://#{CMS::S3.options[:bucket]}/"
    prefixes_to_exclude = ([Account.master] + Account.providers).map{|p| "#{bucket}#{p.s3_provider_prefix}/"}

    files_to_remove = `s3cmd ls #{bucket}`
    full_paths_of_files_to_remove = files_to_remove.map{|line| line.split(/\s+/).last}.reject{|line| prefixes_to_exclude.include?(line)}

    full_paths_of_files_to_remove.each do |file|
      system "echo s3cmd del -r #{file}"
      system "s3cmd del -r #{file}"
    end
  end

  desc 'move invoices to match the MT multiplier'
  task 'move_invoices' => :environment do
    Invoice.find(:all, :conditions => "pdf_file_name IS NOT NULL").each do |invoice|
      begin
        open(invoice.pdf.expiring_url)
      rescue OpenURI::HTTPError
        multiplier = MULTIPLIERS[invoice.provider_account.id] || invoice.provider_account_id / 16
        original_id = invoice.id
        new_url = "s3://#{invoice.pdf.url.match(/s3.amazonaws.com\/(.*)\?/)[1]}"
        invoice.id = invoice.id / multiplier
        begin
          old_url = "s3://#{invoice.pdf.url.match(/s3.amazonaws.com\/(.*)\?/)[1]}"
          open(invoice.pdf.expiring_url)
          puts "Moving #{old_url} to #{new_url}"
          system("s3cmd cp #{old_url} #{new_url}")
        rescue OpenURI::HTTPError
          puts "Failing: #{invoice.pdf.url}"
        end
      end
    end
  end

  desc 'regenerates missing invoices in the MT compatible bucket'
  task :s3_invoices => :environment do
    Invoice.find(:all, :conditions => "pdf_file_name IS NOT NULL").each do |invoice|
      next unless invoice.provider_account
      retry_once = true
      begin
        open(invoice.pdf.expiring_url)
      rescue OpenURI::HTTPError
        invoice.generate_pdf!
      rescue StandardError => e
        if retry_once
          retry_once = false
          retry
        else
          next # I believe some urls in the DB are weird and always fail
        end
      end
    end
  end

  desc 'joins existing redirects to the first provider in the db'
  task :redirects => :environment do
    provider = Account.providers.first
    Redirect.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned Redirects point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing html_blocks and versions to the first provider in the db'
  task :html_blocks => :environment do
    provider = Account.providers.first


    HtmlBlock.update_all "account_id = #{provider.id}", "account_id is NULL"
    HtmlBlock::Version.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned HtmlBlocks and versions point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing file_blocks and versions to the first provider in the db'
  task :file_blocks => :environment do
    provider = Account.providers.first

    FileBlock.update_all "account_id = #{provider.id}", "account_id is NULL"
    FileBlock::Version.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned FileBlocks and versions point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing file attachments and versions to the first provider in the db'
  task :file_attachments => :environment do
    provider = Account.providers.first
    FileAttachment.update_all "account_id = #{provider.id}", "account_id is NULL"
    FileAttachment::Version.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned FileAttachments and versions point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing image_blocks and versions to the first provider in the db'
  task :image_blocks => :environment do
    provider = Account.providers.first

    ImageBlock.update_all "account_id = #{provider.id}", "account_id is NULL"
    ImageBlock::Version.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned ImageBlocks and versions point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing portlets to the first provider in the db'
  task :portlets => :environment do
    provider = Account.providers.first

    sql = %{ delete from portlets where type not in ('#{Portlet.types.join("', '")}') }
    ActiveRecord::Base.connection.execute(sql)
    puts "~ BCMS orphaned Portlets of non-existant types removed from db"

    Portlet.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned Portlets point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing tags to the first provider in the db'
  task :tags => :environment do
    provider = Account.providers.first

    Tag.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned Tags point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing category_types to the first provider in the db'
  task :category_types => :environment do
    provider = Account.providers.first

    CategoryType.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned CategoryTypes point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing categories to the first provider in the db'
  task :categories => :environment do
    provider = Account.providers.first

    Category.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned Categories point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing blogs to the first provider in the db'
  task :blogs => :environment do
    provider = Account.providers.first

    Blog.update_all "account_id = #{provider.id}", "account_id is NULL"
    Blog::Version.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned Blogs point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing blog_posts to the first provider in the db'
  task :blog_posts => :environment do
    provider = Account.providers.first

    BlogPost.update_all "account_id = #{provider.id}", "account_id is NULL"
    BlogPost::Version.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned BlogPosts point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing dynamic_views to the first provider in the db'
  task :dynamic_views => :environment do
    provider = Account.providers.first

    DynamicView.update_all "account_id = #{provider.id}", "account_id is NULL"
    PageTemplate::Version.update_all "account_id = #{provider.id}", "account_id is NULL"
    EmailTemplate::Version.update_all "account_id = #{provider.id}", "account_id is NULL"
    PagePartial::Version.update_all "account_id = #{provider.id}", "account_id is NULL"


    puts "~ BCMS orphaned DynamicViews point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing groups to the first provider in the db'
  task :groups => :environment do
    provider = Account.providers.first

    Group.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned Groups point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing links to the first provider in the db'
  task :links => :environment do
    provider = Account.providers.first

    Link.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned Links point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing pages to the first provider in the db'
  task :pages => :environment do
    provider = Account.providers.first

    Page.update_all "account_id = #{provider.id}", "account_id is NULL"
    # Page::Version.update_all "account_id = #{provider.id}", "account_id is NULL"
    # Page.all.each do |page|
    #   page.update_attribute :account_id, provider.id
    # end

    puts "~ BCMS orphaned Pages point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'adds extension to pages page_template_file field'
  task :fix_pages => :environment do
    wrong_layouts = Page.all.map(&:template_file_name).uniq.delete_if { |l| l =~ /liquid$/ }

    wrong_layouts.each do |layout|
      pages = Page.scoped(:conditions => "template_file_name like '%#{layout}'")
      pages.update_all "template_file_name = '#{layout}.liquid'"
    end

    puts "~ all BCMS Pages have page_template_file with extension .liquid"
  end

  desc 'joins existing sections to the first provider in the db'
  task :sections => :environment do
    provider = Account.providers.first

    Section.update_all "account_id = #{provider.id}", "account_id is NULL"
    SectionNode.update_all "account_id = #{provider.id}", "account_id is NULL"

    puts "~ BCMS orphaned Sections point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'joins existing legal_term_acceptances to the first provider in the db'
  task :legal_term_acceptances => :environment do
    provider = Account.providers.first

    puts "~ BCMS orphaned LegalTermAcceptances point to provider #{provider.id}:'#{provider.org_name}'"
  end

  desc 'puts s3_prefix to the providers that do not have it in the database'
  task :add_s3_prefix_to_providers => :environment do
    Account.providers.select{|p| !p.s3_prefix}.each do |provider|
      provider.generate_s3_prefix
      provider.save!
      puts "Provider #{provider.org_name} has prefix #{provider.s3_prefix}"
    end

    m = Account.master
    m.generate_s3_prefix
    m.save!
  end

end
