require 'json'

module Polyblock
  class Block < ActiveRecord::Base
    attr_accessor :settings_cache
    DEFAULTS = {
      :association => {
          :class_name => "Polyblock::Block",
          :as => :contentable,
          :dependent => :destroy
      },
      :nested_attributes => {},
      :validates => {},
      :html => true,
      :default_text => "[Editable content space for Polyblock <code>#{name}</code>]"
    }

    belongs_to :contentable, :polymorphic => true
    before_save :strip_html_if_necessary

    def self.import(pbs)
      outputs = pbs.map do |pb|
        block = fetch_or_initialize pb['name']
        block.content = pb['content'] if pb.key?('content') && pb['content'].present? && pb['content'] != block.content
        block.save
      end
      outputs.include?(false)
    end

    def self.export
      output = all.as_json(:except => [:id, :created_at, :updated_at])
      puts ""
      puts "Run the following in Rails Console on the remote server:"
      puts ""
      puts "Polyblock::Block.import(#{output})"
      puts ""
    end

    def settings
      return self.settings_cache unless self.settings_cache.nil?
      self.settings_cache = self.contentable.present? ? self.contentable.send("#{self.name}_settings") : DEFAULTS
    end

    def to_s
      return nil if self.content.nil?
      self.class.strip_html(self.content) end

    def present?
      !nil? && content.present?
    end

    def blank?
      nil? || content.blank?
    end

    def system?
      self.contentable.nil?
    end

    def self.fetch_or_initialize(name)
      if name.is_a? Block
        name
      elsif name.is_a? String
        matches = where :name => name
        if matches.any?
          matches.first
        else
          new({:name => name})
        end
      end
    end
    def self.fetch_or_create(name)
      pb = fetch_or_initialize(name)
      pb.save if pb.new_record?
      pb
    end

    def self.next_id
      any? ? maximum(:id).next : 1
    end
    def self.random_id
      o = [('a'..'z'), ('A'..'Z')].map { |i| i.to_a }.flatten
      (0...50).map { o[rand(o.length)] }.join
    end

    def self.strip_html(str)
      return str unless str.present?
      output = str.gsub('<br><br>', '<br>').gsub('&nbsp;', ' ')
      output = CGI.unescapeHTML(output)
      output = ActionController::Base.helpers.strip_tags(output)
      output.html_safe
    end

    private
    def strip_html_if_necessary
      self.content = Block.strip_html(self.content) unless self.settings[:html] || self.content.nil?
    end

  end
end