class Api::Pm::IssuesController < Api::Pm::BaseController
  before_action :require_login, except: [:index]
  before_action :load_project
  before_action :load_issue, only: %i[show update destroy link_index link_issues parent_issues]
  before_action :load_issues, only: %i[batch_update batch_destroy]
  before_action :check_issue_operate_permission, only: %i[update destroy]

  def index
    @object_result = Api::V1::Issues::ListService.call(@project, query_params, current_user)
    @total_issues_count = @object_result[:total_issues_count]
    @opened_issues_count = @object_result[:opened_issues_count]
    @closed_issues_count = @object_result[:closed_issues_count]
    @complete_issues_count = @object_result[:complete_issues_count]
    if params[:only_name].present?
      @issues = kaminary_select_paginate(
        @object_result[:data].select(:id, :subject, :project_issues_index, :updated_on, :created_on))
    else
      @issues = kaminari_paginate(@object_result[:data])
    end
    render 'api/v1/issues/index'
  end

  def link_index
    pm_issue_type = params[:pm_issue_type] || [1, 2, 3]
    not_join_id = case params[:issue_filter_type]
                  when 'leaf_issue'
                    Issue.where(root_id: @issue.id).pluck(:id)
                  when 'link_issue'
                    @issue.pm_links.pluck(:be_linkable_id)
                  end

    not_join_id << @issue.id
    object_issues = Issue.where(
      pm_project_id: params[:pm_project_id],
      pm_issue_type: pm_issue_type
    ).where.not(id: not_join_id).order(updated_on: :desc)

    object_issues = object_issues.where(root_id: nil, child_count: 0) if params[:issue_filter_type] == 'leaf_issue'
    @issues = kaminari_paginate(object_issues)
    render 'api/v1/issues/index'
  end

  def parent_issues
    @issues = Issue.where(pm_project_id: params[:pm_project_id])
                   .where.not(id: @issue.id)
                   .where.not(id: Issue.full_children_issues(@issue).map{|i|i.id}) 
    @issues = @issues.where(pm_issue_type: params[:pm_issue_type]) if params[:pm_issue_type].present?
    @issues = @issues.ransack(id_or_project_issues_index_eq: params[:keyword]).result.or(@issues.ransack(subject_or_description_cont: params[:keyword]).result) if params[:keyword].present?
    @issues = @issues.reorder("#{issue_sort_by} #{issue_sort_direction}")
    if params[:only_name].present?
      @issues = kaminary_select_paginate(
        @issues.select(:id, :subject, :project_issues_index, :updated_on, :created_on))
    else
      @issues = @issues.includes(:priority, :issue_status, :user, :show_assigners, :show_issue_tags, :version, :comment_journals)
      @issues = kaminari_paginate(@issues)
    end
  end

  def show
    @issue.associate_attachment_container
    render 'api/v1/issues/show'
  end

  def create
    @object_result = Api::Pm::Issues::CreateService.call(@project, issue_params, current_user)
    render 'api/v1/issues/create'
  end

  def update
    @object_result = Api::Pm::Issues::UpdateService.call(@project, @issue, issue_params, current_user)
    render 'api/v1/issues/update'
  end

  def batch_update
    @object_result = Api::Pm::Issues::BatchUpdateService.call(@project, @issues, batch_issue_params, current_user)
    if @object_result
      render_ok
    else
      render_error('批量更新疑修失败！')
    end
  end

  def batch_destroy
    return render_ok if params[:ids].is_a?(Array) && params[:ids].blank?
    @object_result = Api::Pm::Issues::BatchDeleteService.call(@project, @issues, current_user)
    if @object_result
      render_ok
    else
      render_error('批量删除疑修失败！')
    end
  end

  def priorities
    @priorities = IssuePriority.order(position: :asc)
    @priorities = @priorities.ransack(name_cont: params[:keyword]).result if params[:keyword]
    @priorities = kaminary_select_paginate(@priorities)
    render "api/v1/issues/issue_priorities/index"
  end

  def tags
    # IssueTag.pm_init_data(params[:pm_project_id]) unless $redis_cache.hget("pm_project_init_issue_tags", params[:pm_project_id])
    @issue_tags = IssueTag.where(pm_project_id: params[:pm_project_id]).reorder("#{tag_sort_by} #{tag_sort_direction}")
    @issue_tags = @issue_tags.ransack(name_cont: params[:keyword]).result if params[:keyword].present?
    params[:only_name] = true #强制渲染 不走project
    @issue_tags = kaminary_select_paginate(@issue_tags.select(:id, :name, :color))
    render "api/v1/issues/issue_tags/index"
  end

  def statues
    @statues = IssueStatus.order("position asc")
    @statues = @statues.ransack(name_cont: params[:keyword]).result if params[:keyword].present?
    @statues = kaminary_select_paginate(@statues)
    render "api/v1/issues/statues/index"
  end



  def destroy
    @object_result = Api::Pm::Issues::DeleteService.call(@project, @issue, current_user)
    if @object_result
      render_ok
    else
      render_error('删除疑修失败！')
    end
  end

  def export 
    return render_error('请输入正确的项目ID.') if params[:pm_project_id].blank?
    Axlsx::Package.new do |p|
      [['requirement', 1], ['task', 2], ['bug', 3]].each do |type|
        p.workbook.add_worksheet(:name => type[0]) do |sheet|
          @issues = Issue.where(pm_project_id: params[:pm_project_id], pm_issue_type: type[1])
          sheet.add_row ["ID", "标题*", "正文", "创建者*", "创建时间", "修改者", "更新时间", "状态", "负责人", "优先级", "标记", "开始时间","结束时间", "预估工时"]
          @issues.each do |issue| 
            sheet.add_row [issue.id, issue.subject, issue.description, issue.user.try(:login), issue.created_on.strftime("%Y-%m-%d %H:%M:%S"), issue.changer.try(:login), issue.updated_on.strftime("%Y-%m-%d %H:%M:%S"), issue.status_id, issue.assigners.pluck(:login).join(","), issue.priority_id, issue.issue_tags.pluck(:name, :color).join(","), issue.start_date.present? ? issue.start_date.strftime("%Y-%m-%d") : "", issue.due_date.present? ? issue.due_date.strftime("%Y-%m-%d") : "", issue.time_scale]
          end
        end
      end
      p.workbook.add_worksheet(:name => 'leaf_relations') do |sheet|
        leaf_issues = Issue.where(pm_project_id: params[:pm_project_id]).where.not(root_id: nil)
        sheet.add_row ["ID", "父工作项ID"]
        leaf_issues.each do |issue| 
          sheet.add_row [issue.id, issue.root_id]
        end
      end
      p.workbook.add_worksheet(:name => 'link_relations') do |sheet| 
        # links = PmLink.joins(:linkable_issue).where(issues: {pm_project_id: params[:pm_project_id]})
        links = PmLink.find_by_sql("SELECT `pm_links`.* FROM `pm_links` INNER JOIN `issues` ON `issues`.`id` = `pm_links`.`linkable_id` AND `pm_links`.`linkable_type` = 'Issue' WHERE `issues`.`pm_project_id` = #{params[:pm_project_id]}")
        sheet.add_row ["ID", "被关联工作项ID"]
        links.each do |link|
          sheet.add_row [link.linkable_id, link.be_linkable_id]
        end
      end
      p.serialize('public/导出工作项.xlsx')
    end

    send_file('public/导出工作项.xlsx', :type => 'application/octet-stream;charset=utf-8')
  end

  def import 
    begin
      return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile)
      return render_error('请输入正确的项目ID.') if params[:pm_project_id].blank?
      return render_error('请输入正确的组织ID.') if params[:organization_id].blank?
      ActiveRecord::Base.transaction do 
        types = {requirement: 1, task: 2, bug: 3}
        doc = SimpleXlsxReader.open(params[:file].tempfile)
        doc.sheets.each do |sheet|
          case sheet.name
          when 'requirement', 'task', 'bug'

            type = types["#{sheet.name}".to_sym]

            sheet.rows.each.with_index do |row, index|
              next if index == 0
              issue = Issue.new(issue_classify: "issue", project_id: 0, pm_project_id: params[:pm_project_id], pm_issue_type: type, tracker_id: Tracker.first.id)
              issue.fake_id = row[0]
              issue.subject = row[1]
              issue.description = row[2]
              author = User.find_by(login: row[3]) 
              issue.user = author 
              issue.created_on = row[4]
              changer = User.find_by(login: row[5])
              issue.changer = changer 
              issue.updated_on = row[6]
              issue.status_id = row[7].to_i
              if row[8].present?
                row[8].split(',').each do |a| 
                  u = User.find_by(login: a)
                  next unless u.present? 
                  issue.assigners << u
                end
              end
              issue.priority_id = row[9]
              if row[10].present? 
                row[10].split(',').each_slice(2).to_a.each do |t|
                  tag = IssueTag.find_by(project_id: 0, organization_id: params[:organization_id], name: t[0])
                  if tag.present? 
                    issue.issue_tags << tag
                  else
                    tag = IssueTag.create(project_id: 0,organization_id: params[:organization_id], name: t[0], color: t[1])
                    issue.issue_tags << tag
                  end
                end
              end
              issue.start_date = row[11]
              issue.due_date = row[12]
              issue.time_scale = row[13]
              issue.save!
            end
          when 'leaf_relations'
            sheet.rows.each.with_index do |row, index|
              next if index == 0
              children_issue = Issue.where(fake_id: row[0]).last
              parent_issue = Issue.where(fake_id: row[1]).last
              next if children_issue.blank? || parent_issue.blank? 
              children_issue.root_id = parent_issue.id
              children_issue.save(touch: false)
            end
          when 'link_relations'
            sheet.rows.each.with_index do |row, index|
              next if index == 0
              link_issue = Issue.where(fake_id: row[0]).last 
              be_link_issue = Issue.where(fake_id: row[1]).last
              next if link_issue.blank? || be_link_issue.blank? 
              PmLink.create!(linkable_type: 'Issue', linkable_id: link_issue.id, be_linkable_type: 'Issue', be_linkable_id: be_link_issue.id)
            end
          else
            return render_error('导入失败，请上传正确格式的excel文件')
          end
          
        end
      end
      render_ok
    rescue 
      return render_error('导入失败，请上传正确格式的excel文件')
    end
  end

  def link_issues
    children_issues = @issue.pm_issue_type == 1 ? @issue.child_count > 0 ? Issue.where(id: @issue.id) : Issue.none : Issue.where(root_id: @issue.id)
    linkable_issues = Issue.where(id: PmLink.where(linkable_type: "Issue", linkable_id: @issue.id).pluck(:be_linkable_id))
    belinkable_issues = Issue.where(id: PmLink.where(be_linkable_type: "Issue", be_linkable_id: @issue.id).pluck(:linkable_id))

    full_link_issues_ids = children_issues.pluck(:id) | linkable_issues.pluck(:id) | belinkable_issues.pluck(:id)
    compare_link_issues_ids = children_issues.pluck(:id) | linkable_issues.pluck(:id) | belinkable_issues.pluck(:id)
    i = compare_link_issues_ids.count
    while i > 0 do 
      children_issues = Issue.where(root_id: compare_link_issues_ids)
      linkable_issues = Issue.where(id: PmLink.where(linkable_type: "Issue", linkable_id: compare_link_issues_ids).pluck(:be_linkable_id))
      belinkable_issues = Issue.where(id: PmLink.where(be_linkable_type: "Issue", be_linkable_id: compare_link_issues_ids).pluck(:linkable_id))

      compare_link_issues_ids = (children_issues.pluck(:id) | linkable_issues.pluck(:id) | belinkable_issues.pluck(:id)) - full_link_issues_ids
      full_link_issues_ids = full_link_issues_ids | compare_link_issues_ids
      i = compare_link_issues_ids.count
    end
    exclude_issues_ids = []
    exclude_issues = Issue.where(id: full_link_issues_ids).where.not(root_id: nil)
    exclude_issues.each do |i| 
      exclude_issues_ids << i.id if i.pm_issue_type == 1 && full_link_issues_ids.include?(i.root_id)
    end
    full_link_issues_ids = full_link_issues_ids - exclude_issues_ids
    @requirement_issues = Issue.where(id:full_link_issues_ids, pm_issue_type:1, root_id: nil).pm_includes
    @task_issues = Issue.where(id:full_link_issues_ids, pm_issue_type:2).pm_includes
    @bug_issues = Issue.where(id:full_link_issues_ids, pm_issue_type:3).pm_includes
  end

  private
  def circle_link_issues(issue_ids)
    if issue_ids.present?
      children_issues = Issue.joins(:parent_issue).where(issues: {id: issue_ids})
      linkable_issues = Issue.where(id: PmLink.where(linkable_type: "Issue", linkable_id: issue_ids))
      belinkable_issues = Issue.where(id: PmLink.where(be_linkable_type: "Issue", be_linkable_id: issue_ids))

      return circle_link_issues(children_issues.pluck(:id))
    else
      return []
    end
  end

  def check_issue_operate_permission
    return if params[:project_id].to_i.zero?
    render_forbidden('您没有操作权限！') unless @project.member?(current_user) || current_user.admin? || @issue.user == current_user
  end

  def load_issue
    # return render_parameter_missing if params[:pm_project_id].blank?
    @issue = Issue.issue_issue.find_by_id(params[:id])
    render_not_found('疑修不存在!') if @issue.blank?
  end

  # def load_issue_by_index
  #   return render_parameter_missing if params[:pm_project_id].blank? || params[:pm_issue_type].blank? || params[:enterprise_identifier].blank?
  #   @issue = Issue.find_issues_by_pm(params[:enterprise_identifier], params[:pm_issue_type])
  #                 .find_by(pm_issue_type_index3: params[:index])
  #   render_not_found('疑修不存在!') if @issue.blank?
  # end

  def load_issues
    return render_error('请输入正确的ID数组！') unless params[:ids].is_a?(Array)
    params[:ids].each do |id|
      @issue = Issue.find_by(id: id, pm_project_id: params[:pm_project_id])
      return render_not_found("ID为#{id}的疑修不存在!") if @issue.blank?
    end
    if params[:ids].blank? 
      @issues = Issue.where(pm_project_id: params[:pm_project_id])
    else
      @issues = Issue.where(id: params[:ids], pm_project_id: params[:pm_project_id])
    end
  end


  def query_params
    params.permit(
      :only_name,
      :category,
      :participant_category,
      :keyword, :author_id,
      :milestone_id, :assigner_id,
      :status_id, :priority_id,
      :begin_date, :end_date,
      :update_begin_date, :update_end_date,
      :sort_by, :sort_direction, :root_id,
      :issue_tag_ids, :pm_project_id, :pm_sprint_id, :pm_issue_type, :pm_project_ids,
      :status_ids, :ids, :exclude_ids, :pm_issue_types, :participator_id, :enterprise_identifier
    )
  end



  def issue_params
    params.permit(
      :status_id, :priority_id, :milestone_id,
      :branch_name, :start_date, :due_date, :time_scale,
      :subject, :description, :blockchain_token_num, :root_subject,
      :pm_project_id, :pm_sprint_id, :pm_issue_type, :root_id, :link_able_id, :project_id,
      :status_msg, :enterprise_identifier,
      issue_tag_ids: [],
      assigner_ids: [],
      attachment_ids: [],
      receivers_login: []
    )
  end

  def batch_issue_params
    params.permit(
      :status_id, :priority_id, :milestone_id, :pm_sprint_id, :due_date, :pm_issue_type, :root_id, :target_pm_project_id, :project_id,
      :issue_tag_ids => [],
      :assigner_ids => [] )
  end

  def issue_sort_by 
    sort_by = params.fetch(:sort_by, "updated_on")
    sort_by = Issue.column_names.include?(sort_by) ? sort_by : "updated_on"
    sort_by
  end

  def issue_sort_direction 
    sort_direction = params.fetch(:sort_direction, "desc").downcase
    sort_direction = %w(desc asc).include?(sort_direction) ? sort_direction : "desc"
    sort_direction
  end

  def tag_sort_by
    sort_by = params.fetch(:sort_by, "created_at")
    sort_by = IssueTag.column_names.include?(sort_by) ? sort_by : "created_at"
    sort_by
  end

  def tag_sort_direction
    sort_direction = params.fetch(:sort_direction, "desc").downcase
    sort_direction = %w(desc asc).include?(sort_direction) ? sort_direction : "desc"
    sort_direction
  end

end
