require 'net/http'
require 'json'
require 'fileutils'
require 'csv'

class ProjectsController < ApplicationController

  include ApplicationHelper
  include DatapackageHelper
  include ProjectHelper

  before_action :authenticate_user!, except: [ :index, :show, :api_detail ]
  before_action :correct_user, only: [ :destroy, :edit, :update ]


  def index
    @projects = Project.order(id: :desc).page params[:page] # kaminari
    @user = current_user
    pids = @projects.ids
    # note that nil is added to list of pids so that we include in our hash any global permissions. We do this
    # because as soon as a global permission is added, it locks down all projects.
    @read_key_hash = ApiKeyPermission.where(project_id: [nil] + pids,permission: [0,1]).group(:project_id).count
    @write_key_hash = ApiKeyPermission.where(project_id: [nil] + pids,permission: 1).group(:project_id).count
  end

  def show
    @project = Project.find(params[:id])
    @datasources = @project.datasources
    @datapackage = @project.datapackage
    # filter API key permissions where the permission is read-write and the
    # scope is either global or specific to the project.
    # key_perms = ApiKeyPermission.where("permission = 1 and (permission_scope = ? or (permission_scope = ? and project_id = ?))",0,1,@project.id)
    @keys_with_write_permission = ApiKey.joins(:api_key_permissions).where("permission = 1 and (permission_scope = ? or (permission_scope = ? and project_id = ?))",0,1,@project.id)
    #binding.pry
    # @datapackage_resources = @datapackage.present? ?  @datapackage.datapackage_resources : nil
    # if there exists a datasource with the same name as a datapackage_resource then it was uploaded
    # @datapackage_resources.each do |dr|
    #   @datasources.any?{ |a| a.datafile_file_name == dr.split("/").last }
    # end
    # log_files = Dir.glob(@project.job_log_path + '*.log')
    # @log_file_names = log_files.map { |l| l.split("/").last }
  end

  def new
    @project = Project.new
  end

  def create
    @project = current_user.projects.build(project_params)
    if @project.save
      flash[:success] = "New project created. Now upload a datapackage.json file."
      Dir.mkdir(@project.job_log_path) unless File.directory?(@project.job_log_path)
      Dir.mkdir(@project.upload_path) unless File.directory?(@project.upload_path)
      # same as: redirect_to project_url(@project)
      redirect_to @project
    else
      render 'new'
    end
  end


  def edit
    @project = Project.find(params[:id])
  end


  def update
    @project = Project.find(params[:id])
    if @project.update_attributes(project_params)
      flash[:success] = "Project updated"
      redirect_to @project
    else
      render 'edit'
    end
  end


  def destroy
    project = Project.find(params[:id])
    if project.datapackage.present?
      project.datapackage.datapackage_resources.each do |dp_res|
        #dp_res.delete_associated_artifacts
        dp_res.delete_db_table
      end
    end
    FileUtils.rm_rf(project.job_log_path)
    FileUtils.rm_rf(project.upload_path)
    if project.destroy
      flash[:success] = "Project deleted"
    else
      flash[:error] = "Failed to delete project"
    end
    redirect_to projects_url
  end


  def upload_datapackage

    @project = Project.find(params[:id])
    @feedback = { errors: [], warnings: [], notes: [] }

    if @project.datapackage.present?
      @feedback[:errors] << datapackage_errors[:already_uploaded]
    elsif params[:datapackage].blank?
      @feedback[:errors] << datapackage_errors[:no_upload]
    else
      datapackage = params[:datapackage]

      json_dp = check_and_clean_datapackage(datapackage)

      # overwrite the datapackage.json temporary file with a clean/trimmed version
      File.open(datapackage.tempfile.path,"w") do |f|
        f.write(json_dp.to_json)
      end

      if json_dp.present? and @feedback[:errors].empty?
        @datapackage = Datapackage.new(project_id: @project.id,
                                       datapackage: File.open(datapackage.tempfile.path),
                                       datapackage_file_name: "datapackage.json")
        if @datapackage.valid?
          save_datapackage(@datapackage)
        else
          @feedback[:errors] += @datapackage.errors.to_a
        end
      end
    end

    if @feedback[:errors].any?
      @project.errors.add(:datapackage, @feedback[:errors])
      render 'edit'
    else
      flash[:success] = "datapackage.json uploaded"
      extract_and_save_datapackage_resources(@datapackage,json_dp)
      create_dp_db_tables(@datapackage) if @feedback[:errors].empty?
      open_read_api(@datapackage)
      redirect_to @project
    end

  end


  def upload_datasources
    @project = Project.find(params[:id])
    @datapackage = @project.datapackage
    @datapackage_resources = @datapackage.present? ?  @datapackage.datapackage_resources : nil
    @feedback = { errors: [], warnings: [], notes: [] }
    @csv_uploads = params[:datafiles]
    @log_file_name = nil

    check_datasources

    unless @feedback[:errors].any?
      @csv_uploads.each do |csv|
        new_datasource = save_datasource(csv)
        # at this point we have saved the csv file and we know there is a
        # corresponding datapackage_resource which points to the metadata
        # required to import the csv file.
        upload_method = params.has_key?("quick-csv-upload") ? "quick" : "slow"
        Delayed::Job.enqueue ProcessCsvUpload.new(new_datasource.id,upload_method) if new_datasource.present?
      end
    end

    if @feedback[:errors].any?
      @project.errors.add(:csv, @feedback[:errors])
      render 'show'
    else
      flash[:success] = "Files uploaded and are being processed. Refresh page for progress..."
      redirect_to @project
    end
  end



  def api_detail
    @project = Project.find(params[:id])
    @datapackage = Datapackage.where(project_id: @project.id).first
    @dp_resources = @datapackage.present? ? @datapackage.datapackage_resources.order(:table_ref) : []
  end



  private


    # Rails strong parameters
    def project_params
      # params.require(:project).permit(:name, :description, datasources: [:datafile_file_name, :table_ref, :public_url])
      params.require(:project).permit(:name, :description) #, datasources: [:datafile_file_name, :table_ref, :public_url])
    end

    def correct_user
      @project = current_user.projects.find_by(id: params[:id])
      redirect_to root_url if @project.nil?
    end


end
