class Ppa::Proposta < ApplicationRecord
	has_paper_trail

	attr_accessor :regiao_id

	attr_default :status, 0
	attr_default :is_problema, false
	attr_default :interna, false

	belongs_to :proposta_combinada, class_name: 'Ppa::Proposta'
	belongs_to :micro_regiao, class_name: 'Ppa::MicroRegiao'
	belongs_to :area_tematica, class_name: 'Ppa::AreaTematica'
	belongs_to :sub_area_tematica, class_name: 'Ppa::SubAreaTematica'
	belongs_to :cidadao, class_name: 'PpaParticipativo::Cidadao'
	belongs_to :ppa, class_name: 'Ppa::Ppa'

	has_one :iniciativa

	has_many :votos_da_proposta, dependent: :destroy
	has_many :propostas_combinadas, class_name: 'Ppa::Proposta', foreign_key: "proposta_combinada_id"
	has_many :votos_da_proposta, dependent: :destroy

	after_initialize :verifica_status, unless: :new_record?
	before_validation :copia_proposta_para_proposta_revisada, on: :create, unless: :is_problema

	validates_presence_of :micro_regiao_id
	validates_presence_of :cidadao_id, unless: Proc.new{ |proposta| proposta.interna }
	validates_presence_of :area_tematica_id
	validates_presence_of :sub_area_tematica_id, unless: Proc.new{ |proposta| proposta.ppa.present? && proposta.ppa.ativar_somente_area_tematica }
	validates_presence_of :regiao_id, unless: Proc.new{|proposta| proposta.ppa.present? && proposta.ppa.ativar_somente_micro_regiao }

	validates_presence_of :proposta_combinada_id, if: Proc.new{ |proposta| proposta.status.present? && proposta.combinada? }
	validates_absence_of :proposta_combinada_id, unless: Proc.new{ |proposta| proposta.status.present? && proposta.combinada? }

	validates_presence_of :descricao, unless: :is_problema
	validates_presence_of :problema, if: :is_problema

	validates_length_of :descricao, minimum: 15, unless: :is_problema
	validates_length_of :proposta_revisada, minimum: 15, unless: :is_problema
	validates_length_of :problema, minimum: 15, if: :is_problema

	validate :imutabilidade_pos_preencher_descricao, unless: Proc.new{ |proposta| proposta.is_problema || proposta.cidadao_id.blank? }

	validate :maximo_de_caracteres_da_descricao, if: Proc.new{ |proposta| proposta.interna == false && proposta.ppa && !proposta.is_problema }
	validate :quantidade_limite_de_propostas_por_cidadao, on: :create, if: Proc.new{ |proposta| proposta.ppa.present? && proposta.ppa.quantidade_limite_de_propostas.present? && !proposta.is_problema && !proposta.interna }

	validate :termos_de_uso, on: :create, unless: Proc.new{ self.interna == true || self.is_problema}

	scope :votaveis,  -> { where(status: [2,3,4]) }
	scope :aprovadas, -> { where(status: 3) }
	scope :sugeridas, -> { where(is_problema: false) }
	scope :problemas, -> { where(is_problema: true) }

	def self.quantidade_problema_por_regiao ppa_id
		where(ppa_id: ppa_id, is_problema: true).includes(micro_regiao: :regiao).group_by { |proposta| proposta.micro_regiao.regiao.nome }.map {|regiao, voto_proposta|
			{nome: regiao, quantidade: voto_proposta.size}
		}
	end

	def self.quantidade_proposta_por_regiao ppa_id
		where(ppa_id: ppa_id, is_problema: false).includes(micro_regiao: :regiao).group_by { |proposta| proposta.micro_regiao.regiao.nome }.map {|regiao, voto_proposta|
			{nome: regiao, quantidade: voto_proposta.size}
		}
	end

	def self.quantidade_problema_por_micro_regiao ppa_id
		where(ppa_id: ppa_id, is_problema: true).includes(:micro_regiao).group_by { |proposta| proposta.micro_regiao.nome}.map {|microrregiao, voto_proposta|
			{nome: microrregiao, quantidade: voto_proposta.size}
		}
	end

	def self.quantidade_proposta_por_micro_regiao ppa_id
		where(ppa_id: ppa_id, is_problema: false).includes(:micro_regiao).group_by { |proposta| proposta.micro_regiao.nome}.map {|microrregiao, voto_proposta|
			{nome: microrregiao, quantidade: voto_proposta.size}
		}
	end

	def self.quantidade_problema_por_area_tematica ppa_id
		where(ppa_id: ppa_id, is_problema: true).includes(:area_tematica).group_by {|proposta| proposta.area_tematica.nome}.map {|area_tematica, voto_area_tematica|
			{nome: area_tematica, quantidade: voto_area_tematica.size}
		}
	end

	def self.quantidade_proposta_por_area_tematica ppa_id
		where(ppa_id: ppa_id, is_problema: false).includes(:area_tematica).group_by {|proposta| proposta.area_tematica.nome}.map {|area_tematica, voto_area_tematica_problema|
			{nome: area_tematica, quantidade: voto_area_tematica_problema.size}
		}
	end

	enum status: {
		em_analise: 0,
		rejeitada: 1,
		em_votacao: 2,
		aprovada: 3,
		nao_aprovada: 4,
		combinada: 5,
		lancada_no_ppa: 6
	}

	def id_e_descricao
		"#{id} - #{descricao}"
	end

	def total_de_votos
		self.votos_da_proposta.count.to_i + self.votos_internos.to_i
	end

	def foi_votada_por?(cidadao)
		voto = Ppa::VotoDaProposta.find_by(cidadao: cidadao, proposta: self)
		voto.present?
	end

	def descricao_revisada
		proposta_revisada || descricao
	end

	def copia_proposta_para_proposta_revisada
		self.proposta_revisada = self.descricao
	end

	def self.relatorio ppa_id, tipo_problema
		tipo_problema = (tipo_problema.present? && tipo_problema == "true")
		dados = ActiveRecord::Base.connection.execute( sql_relatorio(ppa_id, tipo_problema) ).to_a
		dados.each do |dado|
			dado['propostas'] = JSON.parse dado['propostas']
		end
		dados
	end

	def self.relatorio_geral_das_propostas ppa_id, regiao=nil, area_tematica=nil
		if regiao.present?
			return resultado_geral_das_propostas_por_regiao( ppa_id )

		elsif area_tematica.present?
			return resultado_geral_das_propostas_por_area_tematica( ppa_id )

		else
			return resultado_geral_das_propostas( ppa_id )

		end
	end

	def self.total_de_votos_das_propostas ppa_id, regiao=nil, area_tematica=nil
		if regiao.present?
			return total_de_votos_das_propostas_por_regiao_e_micro_regiao( ppa_id )

		elsif area_tematica.present?
			return total_de_votos_das_propostas_por_area_tematica_e_sub_area_tematica( ppa_id )
		end
	end

	private
	def termos_de_uso
		if cidadao.present? && ppa.habilitar_termos_de_uso && !cidadao.aceitou_os_termos_de_uso
			errors.add(:cidadao_id, "Você não pode enviar propostas sem aceitar os termos de uso")
		end
	end

	def verifica_status
		self.update(status: 'aprovada') if (self.lancada_no_ppa? && self.iniciativa.blank?)
	end


	def quantidade_limite_de_propostas_por_cidadao
		if ppa.quantidade_limite_de_propostas.to_i > 0 && self.cidadao_id.present?
			qtd_de_propostas_do_cidadao = Ppa::Proposta.where(cidadao_id: self.cidadao_id, is_problema: false).count.to_f
			errors.add(:cidadao_id, "Você já excedeu o limite de envio de propostas. (#{ppa.quantidade_limite_de_propostas.to_i} por munícipe)") if ( qtd_de_propostas_do_cidadao >= self.ppa.quantidade_limite_de_propostas.to_f )
		end
	end


	def maximo_de_caracteres_da_descricao
		if ppa.quantidade_de_caracteres_das_propostas.to_i > 0
			errors.add(:descricao, "é muito longo (máximo: #{ppa.quantidade_de_caracteres_das_propostas.to_i} caracteres)") if descricao.length > ppa.quantidade_de_caracteres_das_propostas.to_i
		end
	end

	def imutabilidade_pos_preencher_descricao
		if self.id.present?
			proposta_banco = Ppa::Proposta.find(self.id)

			if proposta_banco.descricao != self.descricao
				errors.add(:descricao, "não é possível alterar a proposta original de um cidadão")
			end
		end
	end

	def self.total_de_votos_das_propostas_por_regiao_e_micro_regiao ppa_id
		dados_do_relatorio = []

		regioes = Ppa::Regiao.where( ppa_id: ppa_id )
		regioes.each { |regiao|
			dados_do_relatorio << {
				nome: regiao.nome.to_s,
				numero_de_votos: regiao.total_de_votos_das_propostas_por_regiao.to_i,
				percentual_de_votos: regiao.percentual_de_votos_da_regiao,
				estilo: {negrito: true}
			}

			regiao.micro_regioes.each { |micro_regiao|
				dados_do_relatorio << {
					nome: micro_regiao.nome.to_s,
					numero_de_votos: micro_regiao.total_de_votos_das_propostas_por_micro_regiao,
					percentual_de_votos: micro_regiao.percentual_de_votos_da_micro_regiao,
					estilo: {tabulacao: {posicoes:[0], quantidade: 3}}
				}
			}

			dados_do_relatorio.push( { adicionar_linha: true } )
		}

		dados_do_relatorio.last.try(:delete, :adicionar_linha)
		return dados_do_relatorio
	end

	def self.total_de_votos_das_propostas_por_area_tematica_e_sub_area_tematica ppa_id
		dados_do_relatorio = []

		areas_tematicas = Ppa::AreaTematica.where( ppa_id: ppa_id )
		areas_tematicas.each { |area_tematica|
			dados_do_relatorio << {
				nome: area_tematica.nome.to_s,
				numero_de_votos: area_tematica.total_de_votos_das_propostas_por_area_tematica.to_i,
				percentual_de_votos: area_tematica.percentual_de_votos_da_area_tematica,
				estilo: {negrito: true}
			}

			area_tematica.sub_areas_tematicas.each { |sub_area_tematica|
				dados_do_relatorio << {
					nome: "#{sub_area_tematica.nome.to_s} - #{sub_area_tematica.funcao.codigo}",
					numero_de_votos: sub_area_tematica.total_de_votos_das_propostas_por_sub_area_tematica,
					percentual_de_votos: sub_area_tematica.percentual_de_votos_da_sub_area_tematica,
					estilo: {tabulacao: {posicoes:[0], quantidade: 3}}
				}
			}

			dados_do_relatorio.push( { adicionar_linha: true } )
		}

		dados_do_relatorio.last.try(:delete, :adicionar_linha)
		return dados_do_relatorio
	end

	def self.resultado_geral_das_propostas_por_regiao ppa_id
		dados_do_relatorio = {}
		propostas_por_regiao = []

		regioes = Ppa::Regiao.where( ppa_id: ppa_id )
		regioes.each { |regiao|
			propostas_por_regiao = []
			regiao.propostas.sugeridas.votaveis.sort_by(&:total_de_votos).reverse.each { |proposta|
				propostas_por_regiao << {
					cidadao: proposta.cidadao.present? ? proposta.cidadao.nome.to_s : 'PROPOSTA INTERNA',
					proposta: "##{proposta.id} - #{proposta.try(:descricao_revisada)}",
					votos_internos: proposta.votos_internos.to_i,
					votos_da_populacao: proposta.try(:votos_da_proposta).try(:count).try(:to_i),
					total_de_votos: proposta.total_de_votos.to_i
				}
			}
			dados_do_relatorio["REGIÃO " + regiao.nome.to_s] = propostas_por_regiao
		}

		return dados_do_relatorio
	end

	def self.resultado_geral_das_propostas_por_area_tematica ppa_id
		dados_do_relatorio = {}
		propostas_por_area_tematica = []

		areas_tematicas = Ppa::AreaTematica.where( ppa_id: ppa_id )
		areas_tematicas.each { |area_tematica|
			propostas_por_area_tematica = []
			area_tematica.propostas.sugeridas.votaveis.sort_by(&:total_de_votos).reverse.each { |proposta|
				propostas_por_area_tematica << {
					cidadao: proposta.cidadao.present? ? proposta.cidadao.nome.to_s : 'PROPOSTA INTERNA',
					proposta: "##{proposta.id} - #{proposta.try(:descricao_revisada)}",
					votos_internos: proposta.votos_internos.to_i,
					votos_da_populacao: proposta.try(:votos_da_proposta).try(:count).try(:to_i),
					total_de_votos: proposta.total_de_votos.to_i
				}
			}
			dados_do_relatorio[area_tematica.nome.to_s] = propostas_por_area_tematica
		}
		return dados_do_relatorio
	end

	def self.resultado_geral_das_propostas ppa_id
			dados_do_relatorio = []

			propostas = Ppa::Proposta.where( ppa_id: ppa_id ).sugeridas.votaveis.sort_by(&:total_de_votos).reverse
			propostas.each { |proposta|
				dados_do_relatorio << {
					cidadao: proposta.cidadao.present? ? proposta.cidadao.nome.to_s : 'PROPOSTA INTERNA',
					proposta: "##{proposta.id} - #{proposta.try(:descricao_revisada)}",
					votos_internos: proposta.votos_internos.to_i,
					votos_da_populacao: proposta.try(:votos_da_proposta).try(:count).try(:to_i),
					total_de_votos: proposta.total_de_votos.to_i
				}
			}

			return dados_do_relatorio
	end

	def self.sql_relatorio(ppa_id, is_problema)
		%Q(
			WITH cte_proposta AS (
			SELECT regiao.nome as regiao
			     , micro_regiao.nome as micro_regiao
			     , area_tematica.nome as area_tematica
			     , COALESCE(subarea_tematica.nome, ' ') as subarea_tematica
			     , CASE WHEN proposta.status = 0 THEN 'Em Análise'
			            WHEN proposta.status = 1 THEN 'Rejeitada'
			            WHEN proposta.status = 2 THEN 'Em Votação'
			            WHEN proposta.status = 3 THEN 'Aprovada'
			            WHEN proposta.status = 4 THEN 'Não Aprovado'
			            WHEN proposta.status = 5 THEN 'Combinada'
			            WHEN proposta.status = 6 THEN 'Lançada no PPA' END AS proposta_status
			     , COALESCE(proposta.proposta_revisada, proposta.descricao) AS proposta
					 , proposta.problema AS problema
					 , cidadao.nome AS cidadao
			  FROM ppa_propostas proposta
				JOIN ppa_ppas ppa ON ppa.id = proposta.ppa_id
			  LEFT JOIN ppa_sub_areas_tematicas subarea_tematica ON subarea_tematica.id = proposta.sub_area_tematica_id
			  JOIN ppa_areas_tematicas area_tematica ON area_tematica.ppa_id = ppa.id
			  JOIN ppa_micro_regioes micro_regiao ON micro_regiao.id = proposta.micro_regiao_id
			  JOIN ppa_regioes regiao ON micro_regiao.regiao_id = regiao.id
			  LEFT JOIN ppa_participativo_cidadaos cidadao ON cidadao.id = proposta.cidadao_id
			 WHERE proposta.ppa_id = #{ppa_id}
			   AND proposta.is_problema = #{is_problema}
			 ) SELECT regiao
			      , micro_regiao
			      , area_tematica
			      , subarea_tematica
			      , json_agg(array[proposta_status, proposta, cidadao, problema]) as propostas
			   FROM cte_proposta
			 GROUP BY 1,2,3,4
			 ORDER BY 1,2,3,4
		)
	end

	def maximo_de_caracteres_da_descricao
		if ppa.quantidade_de_caracteres_das_propostas.to_i > 0
			errors.add(:descricao, "é muito longo (máximo: #{ppa.quantidade_de_caracteres_das_propostas.to_i} caracteres)") if descricao.length > ppa.quantidade_de_caracteres_das_propostas.to_i
		end
	end

	def imutabilidade_pos_preencher_descricao
		errors.add(:descricao, "não é possível alterar a proposta original de um cidadão") if self.descricao_was && (self.descricao_was != self.descricao)
	end
end
