module Contabilidade
	class MedicoesDaObraController < ApplicationController
		include ControllerConcern
		include Contabilidade::ObrasHelper
		include ObraControllersConcern

		skip_before_action :verifica_se_tem_orcamento_na_sessao!, only: [:medir, :enviar_medicao, :editar_itens_do_servico_externo, :atualizar_itens_do_servico_externo, :show_medicao], raise: false
		skip_before_action :verifica_se_sessao_eh_de_obra!, only: [:medir, :enviar_medicao, :editar_itens_do_servico_externo, :atualizar_itens_do_servico_externo, :show_medicao], raise: false
		before_action -> { verifica_modulo_na_sessao(["contabilidade", "administrativo", "obra"]) }, except: [:medir, :enviar_medicao, :editar_itens_do_servico_externo, :atualizar_itens_do_servico_externo, :show_medicao]
		before_action :authenticate_usuario!, except: [:medir, :enviar_medicao, :editar_itens_do_servico_externo, :atualizar_itens_do_servico_externo, :show_medicao]
		before_action :autoriza_usuario!, except: [:editar_itens_do_servico, :atualizar_itens_do_servico, :confirmar, :voltar_para_aberta, :enviar_para_cef, :liberar_pela_cef, :convidar, :medir, :enviar_medicao, :editar_itens_do_servico_externo, :atualizar_itens_do_servico_externo, :show_medicao, :reenviar_email]
		before_action :set_medicao_da_obra, only: [:show, :edit, :update, :destroy, :editar_itens_do_servico, :atualizar_itens_do_servico, :confirmar, :voltar_para_aberta, :enviar_para_cef, :liberar_pela_cef, :editar_itens_do_servico_externo, :atualizar_itens_do_servico_externo, :reenviar_email, :lancar, :retornar_para_a_liquidar]
		before_action :set_obra, only: [:new, :create, :convidar]
		before_action :disponibiliza_dependencias, only: [:new, :edit]
		# before_action -> {verifica_mes_bloqueado(@medicao_da_obra)}, only: [:edit, :destroy, :retornar_para_a_liquidar, :voltar_para_aberta]

		# GET /contabilidade/medicoes_da_obra
		def index
			@q = Contabilidade::MedicaoDaObra.left_outer_joins(:liquidacoes).where( :contabilidade_liquidacoes => { :medicao_da_obra_id => nil } ).confirmada.order(:id).search(params[:q])
			@medicoes_da_obra = @q.result(distinct: false)

			@engenheiros_da_obra = Base::TipoDePessoa.find_by(codigo: '1').pessoas.order(:nome)
			@empresas_responsaveis = Base::Pessoa.includes(:tipo_de_pessoa).fornecedores
		end

		# GET /contabilidade/medicoes_da_obra/1
		def show
		end

		# GET /contabilidade/medicoes_da_obra/new
		def new
			@medicao_da_obra = @obra.medicoes_da_obra.new

			if !@obra.engenheiro_responsavel.present?
				redirect_to rota_obra(@obra), alert: 'Para lançar uma medição deve-se primeiro cadastrar o engenheiro responsável.'
			elsif @obra.saldo_para_medicoes.to_f <= 0
				redirect_to rota_obra(@obra), alert: 'Saldo insuficiente para realizar medição.'
			end
		end

		# GET /contabilidade/medicoes_da_obra/1/edit
		def edit
			if @medicao_da_obra.foi_liquidada?
				redirect_to rota_obra(@medicao_da_obra.obra), alert: 'Esta medição já foi liquidada, portanto não pode ser editada. Para realizar a edição é necessário estornar a liquidação.'
			end
		end

		# POST /contabilidade/medicoes_da_obra
		def create
			@medicao_da_obra = @obra.medicoes_da_obra.new(medicao_da_obra_params)

			if @medicao_da_obra.save
				redirect_to contabilidade_medicao_da_obra_path(@medicao_da_obra), notice: 'Medicao da obra foi criado(a) com sucesso.'
			else
				disponibiliza_dependencias
				render :new
			end
		end

		# PATCH/PUT /contabilidade/medicoes_da_obra/1
		def update
			if @medicao_da_obra.update( medicao_da_obra_params )
				redirect_to contabilidade_medicao_da_obra_path(@medicao_da_obra), notice: 'Medicao da obra foi atualizado(a) com sucesso.'
			else
				disponibiliza_dependencias
				render :edit
			end
		end

		# DELETE /contabilidade/medicoes_da_obra/1
		def destroy
			if !@medicao_da_obra.foi_liquidada?
				mensagem = apaga_e_retorna_mensagem(@medicao_da_obra)
				redirect_to rota_obra(@medicao_da_obra.obra), mensagem
			else
				redirect_to rota_obra(@medicao_da_obra.obra), alert: 'Esta medição já foi liquidada, portanto não pode ser excluída. Para realizar a edição é necessário estornar a liquidação.'
			end
		end

		# PATCH /contabilidade/medicoes_da_obra/1/enviar_para_cef
		def enviar_para_cef
			return if bloqueia_usuario_com_base_em 'update'
			if @medicao_da_obra.enviar_para_cef!
				redirect_to @medicao_da_obra, notice: 'Medição enviada para CEF.'
			else
				redirect_to @medicao_da_obra, alert: "Não foi possível realizar essa ação."
			end
		end
		# PATCH /contabilidade/medicoes_da_obra/1/liberar_pela_cef
		def liberar_pela_cef
			return if bloqueia_usuario_com_base_em 'update'
			if @medicao_da_obra.liberar_pela_cef!
				redirect_to @medicao_da_obra, notice: 'Medição foi liberada pela CEF.'
			else
				redirect_to @medicao_da_obra, alert: "Não foi possível realizar essa ação."
			end
		end

		# PATCH /contabilidade/medicoes_da_obra/1/confirmar
		def confirmar
			return if bloqueia_usuario_com_base_em 'update'
      if @medicao_da_obra.confirmar!
        if Configuracao.last.enviar_relatorio_de_medicao?
          enviar_documento_da_medicao_da_obra(@medicao_da_obra.id)
          redirect_to @medicao_da_obra, success: "Medição confirmada com sucesso, relatório enviado por e-mail"
        else
          redirect_to @medicao_da_obra, success: "Medição confirmada com sucesso"
        end
      else
        if @medicao_da_obra.errors[:base].present?
          mensagem_erro = "Não foi possível Confirmar. #{@medicao_da_obra.errors[:base].join.to_s}"
        else
          mensagem_erro = "Não foi possível realizar essa ação."
        end
        redirect_to @medicao_da_obra, alert: mensagem_erro
      end
		end

		# PATCH /contabilidade/medicoes_da_obra/1/voltar_para_aberta
		def voltar_para_aberta
			return if bloqueia_usuario_com_base_em 'update'
			begin
				if  @medicao_da_obra.voltar_para_aberta!
					redirect_to @medicao_da_obra, success: "A Medição foi reaberta."
				else
					alerta = @medicao_da_obra.errors.any? ? @medicao_da_obra.errors[:base].join(",") : "Não foi possível realizar essa ação."
					redirect_to @medicao_da_obra, alert: alerta
				end
			rescue => e
				flash.now[:alert] = e.message
				render :show
			end
		end

		def retorna_dados_da_medicao
			medicao_da_obra = ::Contabilidade::MedicaoDaObra.find( params[:medicao_da_obra_id] )
			valor_da_medicao = medicao_da_obra.try(:valor).to_f
			saldo_a_liquidar = medicao_da_obra.try(:saldo_a_liquidar).to_f
			render json: {'valor_da_medicao': valor_da_medicao.to_f.real_contabil,
										'saldo_a_liquidar': saldo_a_liquidar.to_f.real_contabil}
		end

		#GET /contabilidade/medicoes_da_obra/1/medir_itens_do_servico
		def editar_itens_do_servico
			return if bloqueia_usuario_com_base_em 'update'

			@medicao_da_obra.obra.itens_do_servico_da_obra.each do |item_do_servico_da_obra|
				item_do_servico_da_medicao_da_obra = @medicao_da_obra.itens_do_servico_da_medicao_da_obra.find_by(item_do_servico_da_obra_id: item_do_servico_da_obra.id)
				@medicao_da_obra.itens_do_servico_da_medicao_da_obra.build(item_do_servico_da_obra_id: item_do_servico_da_obra.id) unless item_do_servico_da_medicao_da_obra.present?
			end
		end

		#PATCH /contabilidade/medicoes_da_obra/1/medir_itens_do_servico
		def atualizar_itens_do_servico
			if params[:contabilidade_medicao_da_obra].present?
				if @medicao_da_obra.update( itens_do_servico_da_medicao_da_obra_params )
					redirect_to contabilidade_medicao_da_obra_path(@medicao_da_obra), notice: 'Medição foi atualizada com sucesso.'
				else
					render :editar_itens_do_servico
				end
			else
				redirect_to contabilidade_medicao_da_obra_path(@medicao_da_obra)
			end
		end

		#GET /contabilidade/medicoes_da_obra/1/medir_itens_do_servico_externo
		def editar_itens_do_servico_externo
			@medicao_da_obra.obra.itens_do_servico_da_obra.each do |item_do_servico_da_obra|
				item_do_servico_da_medicao_da_obra = @medicao_da_obra.itens_do_servico_da_medicao_da_obra.find_by(item_do_servico_da_obra_id: item_do_servico_da_obra.id)
				@medicao_da_obra.itens_do_servico_da_medicao_da_obra.build(item_do_servico_da_obra_id: item_do_servico_da_obra.id) unless item_do_servico_da_medicao_da_obra.present?
			end
			render layout: 'layouts/login'
		end

		#PATCH /contabilidade/medicoes_da_obra/1/medir_itens_do_servico_externo
		def atualizar_itens_do_servico_externo
			if @medicao_da_obra.update( itens_do_servico_da_medicao_da_obra_params )
				redirect_to contabilidade_show_medicao_path(codigo_de_acesso: @medicao_da_obra.codigo_de_acesso), notice: 'Medição foi atualizada com sucesso.'
			else
				render :editar_itens_do_servico_externo, layout: 'layouts/login'
			end
		end

		# PATCH /contabilidade/medicoes_da_obra/convidar
		def convidar
			return if bloqueia_usuario_com_base_em 'update'
			if @obra.servicos_da_obra.any? && !@obra.fiscal_da_obra.nil? && !@obra.responsavel_na_empresa.nil?
				if @obra.contrato.pessoa.email.present?
					@medicao_da_obra = @obra.medicoes_da_obra.new
					@medicao_da_obra.save(validate: false)
					if @medicao_da_obra.convidar
						redirect_to contabilidade_obra_path(@obra), notice: "#{@obra.contrato.try(:cpf_ou_cnpj_e_nome)} foi convidada por e-mail a enviar a medição."
					else
						redirect_to contabilidade_obra_path(@obra) + "?tab=medicoes_da_obra", alert: "Fornecedor não tem e-mail informado, altere o cadastro informando um e-mail válido."
					end
				else
					redirect_to contabilidade_obra_path(@obra) + "?tab=medicoes_da_obra", alert: "Fornecedor não tem e-mail cadastrado."
				end
			else
				redirect_to contabilidade_obra_path(@obra) + "?tab=medicoes_da_obra", alert: "Obra não tem Serviços do Cronograma ou Responsáveis Cadastrados, ajuste o cadastro para solicitar medição por e-mail."
			end
		end

		# PATCH /contabilidade/medicoes_da_obra/reenviar_email
		def reenviar_email
			return if bloqueia_usuario_com_base_em 'update'
			if @medicao_da_obra.convidar
				redirect_to contabilidade_obra_path(@medicao_da_obra.obra), notice: "#{@medicao_da_obra.obra.contrato.try(:cpf_ou_cnpj_e_nome)} foi solicitada por e-mail a enviar a medição."
			else
				redirect_to contabilidade_obra_path(@medicao_da_obra.obra) + "?tab=medicoes_da_obra", alert: "Fornecedor não tem e-mail informado, altere o cadastro informando um e-mail válido."
			end
		end

		def medir
			@configuracao = Configuracao.last
			@codigo_de_acesso = params[:codigo_de_acesso]
			@medicao_da_obra = Contabilidade::MedicaoDaObra.find_by_codigo_de_acesso(@codigo_de_acesso)
			@medicao_da_obra.solicitacoes_por_email.first.respondido?

			if @medicao_da_obra.present?
				if @medicao_da_obra.validade_codigo_de_acesso < Date.today
					@mensagem = "O prazo para enviar essa essa medição expirou, entre em contato com o setor responsável."
					render 'contabilidade/medicoes_da_obra/medir_mensagem', layout: 'layouts/login'
				elsif @medicao_da_obra.medicao_por_email_respondida? && @codigo_de_acesso.present?
					@mensagem = "Medição já preenchia, caso deseje alterar entre em contato com o setor responsável."
					render 'contabilidade/medicoes_da_obra/medir_mensagem', layout: 'layouts/login'
				else
					disponibiliza_dependencias
					render :edit, layout: 'layouts/login'
				end
			else
				@mensagem = "Solicitação não encontrada, verifique se o código de acesso informado é válido."
				render 'contabilidade/medicoes_da_obra/medir_mensagem', layout: 'layouts/login'
			end
		end

		def show_medicao
			@codigo_de_acesso = params[:codigo_de_acesso]
			@medicao_da_obra = Contabilidade::MedicaoDaObra.find_by_codigo_de_acesso(@codigo_de_acesso)
			redirect_to acesso_negado_path and return unless @medicao_da_obra
			render :show_medicao, layout: 'layouts/login'
		end

		# PATCH/PUT /contabilidade/medicoes_da_obra/1
		def enviar_medicao
			@configuracao = Configuracao.last
			@codigo_de_acesso = params[:contabilidade_medicao_da_obra][:codigo_de_acesso]
			@medicao_da_obra = Contabilidade::MedicaoDaObra.find_by_codigo_de_acesso(@codigo_de_acesso)

			if @medicao_da_obra.nil? || @medicao_da_obra.validade_codigo_de_acesso < Date.today
				@mensagem = "O prazo para enviar essa medição expirou ou você não possui permissão para enviar, entre em contato com o setor responsável."
				render 'contabilidade/medicoes_da_obra/medir_mensagem', layout: 'layouts/login'
			else
				if @medicao_da_obra.update( medicao_da_obra_params )
					@medicao_da_obra.atualiza_solicitacao_de_email
					redirect_to contabilidade_editar_itens_do_servico_externo_path(id: @medicao_da_obra.id), notice: 'Cotação atualizada com sucesso e comprovante enviado por e-mail'
				else
					disponibiliza_dependencias
					render :edit, layout: 'layouts/login'
				end
			end
		end

		def lancar
			ActiveRecord::Base.transaction do
				@medicao_da_obra.modulo_atual = session[:modulo]
				if @medicao_da_obra.lancar!
					redirect_to @medicao_da_obra, notice: "Medição Lançada com Sucesso"
				else
					redirect_to @medicao_da_obra, alert: "Não foi possível lançar a medição #{@medicao_da_obra.errors.full_messages.join(',')}"
				end
			end
		end

		# PATCH contabilidade/medicoes_da_obra/1/retornar_para_a_liquidar
		def retornar_para_a_liquidar
			if @medicao_da_obra.voltar_para_confirmado!
				redirect_to @medicao_da_obra, notice: "Voltou Etapa de Medição com Sucesso"
			else
				redirect_to @medicao_da_obra, alert: "Não foi possível voltar etapa da medição #{@medicao_da_obra.errors.full_messages.join(',')}"
			end
		end

		private
		def set_medicao_da_obra
			@medicao_da_obra = Contabilidade::MedicaoDaObra.find( params[:id] )
		end

		def set_obra
			@obra = Contabilidade::Obra.find( params[:obra_id] )
		end

		def disponibiliza_dependencias
			@pessoas = Base::TipoDePessoa.find_by(codigo: '1').pessoas

			obra = @medicao_da_obra.try(:obra) || @obra
			@engenheiros_da_obra = obra.engenheiros_da_obra.where(contabilidade_engenheiros_da_obra: {tipo: Contabilidade::EngenheiroDaObra.tipos[:fiscal]})
			@responsaveis_na_empresa = obra.engenheiros_da_obra.where(contabilidade_engenheiros_da_obra: {tipo: Contabilidade::EngenheiroDaObra.tipos[:responsavel_na_empresa]})
			@empenhos = obra.empenhos.confirmado.map { |empenho|
				[
					empenho.numero_e_contratado,
					empenho.id,
					{
						"data-fonte-de-recursos" => empenho.fonte_de_recursos_codigo_e_descricao,
						"saldo": empenho.saldo
					}
				]
			}
		end


		# Permite apenas os parâmetros específicos
		def medicao_da_obra_params
			params.require(:contabilidade_medicao_da_obra).permit(:obra_id, :numero, :valor, :data_inicial, :data_final, :responsavel_da_empresa_id, :responsavel_da_prefeitura_id, :engenheiro_responsavel_id, :art, :historico,
				empenhos_da_medicao_da_obra_attributes: [:id, :empenho_id, :valor, :medicao_da_obra_id, :_destroy])
		end

		def itens_do_servico_da_medicao_da_obra_params
			params.require(:contabilidade_medicao_da_obra).permit(itens_do_servico_da_medicao_da_obra_attributes: [:id, :item_do_servico_da_obra_id, :quantidade_medida, :total, :_destroy])
		end
	end
end
