class Api::V1::Issues::ListService < ApplicationService
  include ActiveModel::Model

  attr_reader :project, :only_name, :category, :participant_category, :keyword, :author_id, :issue_tag_ids
  attr_reader :begin_date, :end_date, :update_begin_date, :update_end_date
  attr_reader :milestone_id, :assigner_id, :status_id, :priority_id, :sort_by, :sort_direction, :current_user, :enterprise_identifier
  attr_reader :pm_project_id, :pm_project_ids, :pm_sprint_id, :root_id, :pm_issue_type, :status_ids, :ids, :exclude_ids, :pm_issue_types
  attr_accessor :queried_issues, :total_issues_count, :closed_issues_count, :opened_issues_count, :complete_issues_count, :participator

  validates :category, inclusion: { in: %w[all opened closed], message: '请输入正确的Category'}
  validates :participant_category, inclusion: { in: %w[all aboutme authoredme assignedme atme], message: '请输入正确的ParticipantCategory'}
  validates :sort_by, inclusion: { in: %w[issues.created_on issues.updated_on issues.blockchain_token_num issue_priorities.position issues.start_date issues.due_date issues.status_id, assigners] , message: '请输入正确的SortBy'}, allow_blank: true
  validates :sort_direction, inclusion: { in: %w[asc desc], message: '请输入正确的SortDirection'}, allow_blank: true
  validates :current_user, presence: true

  def initialize(project, params, current_user = nil)
    @project = project
    @only_name = params[:only_name]
    @category = params[:category] || 'all'
    @participant_category = params[:participant_category] || 'all'
    @keyword = params[:keyword]
    @author_id = params[:author_id]
    @issue_tag_ids = params[:issue_tag_ids].present? ? params[:issue_tag_ids].split(',') : []
    @milestone_id = params[:milestone_id]
    @assigner_id = params[:assigner_id]
    @priority_id = params[:priority_id]
    @status_id = params[:status_id]
    @begin_date = params[:begin_date]
    @end_date = params[:end_date]
    @update_begin_date = params[:update_begin_date]
    @update_end_date = params[:update_end_date]
    @sort_by = params[:sort_by].present? ?  params[:sort_by] : 'issues.updated_on'
    @enterprise_identifier = params[:enterprise_identifier]
    @pm_project_id = params[:pm_project_id]
    @pm_project_ids = params[:pm_project_ids]
    @pm_sprint_id = params[:pm_sprint_id]
    @root_id = params[:root_id]
    @pm_issue_type = params[:pm_issue_type]
    @ids = params[:ids]
    @exclude_ids = params[:exclude_ids]
    @status_ids = params[:status_ids].present? ? params[:status_ids].split(',') : []
    @pm_issue_types = params[:pm_issue_types].present? ? params[:pm_issue_types].split(',') : []
    @sort_direction = (params[:sort_direction].present? ? params[:sort_direction] : 'desc').downcase
    @participator = params[:participator_id].present? ? User.find_by_id(params[:participator_id]) : current_user
    @current_user = current_user
  end

  def call 
    raise Error, errors.full_messages.join(', ') unless valid? 
    # begin
    issue_query_data

    {
      data: queried_issues, 
      total_issues_count: @total_issues_count, 
      closed_issues_count: @closed_issues_count, 
      opened_issues_count: @opened_issues_count,
      complete_issues_count: @complete_issues_count
    }
    # rescue 
    #   raise Error, "服务器错误，请联系系统管理员！"
    # end
  end

  private 
  def issue_query_data 
    issues = @project&.id.zero? ? Issue.issue_issue : @project.issues.issue_issue
    @total_issues_count = pm_project_id.present? ? issues.where(pm_issue_type:[1, 2, 3]).count : issues.count
    case participant_category
    when 'aboutme' # 关于我的
      issues = issues.joins(:issue_participants).where(issue_participants: {participant_type: %w[authored assigned atme], participant_id: participator&.id})
    when 'authoredme' # 我创建的
      issues = issues.joins(:issue_participants).where(issue_participants: {participant_type: 'authored', participant_id: participator&.id})
    when 'assignedme' # 我负责的
      issues = issues.joins(:issue_participants).where(issue_participants: {participant_type: 'assigned', participant_id: participator&.id})
    when 'atme' # @我的
      issues = issues.joins(:issue_participants).where(issue_participants: {participant_type: 'atme', participant_id: participator&.id})
    end
    # author_id
    issues = issues.where(author_id: author_id) if author_id.present?

    # issue_tag_ids
    if issue_tag_ids.present? 
      if issue_tag_ids.include?('-1')
        issues = issues.where(issue_tags_value: nil).or(issues.where(issue_tags_value: ""))
      else 
        issues = issues.ransack(issue_tags_value_cont: issue_tag_ids.sort!.join(',')).result
      end
    end
    
    # milestone_id
    if milestone_id.present? 
      if milestone_id.to_i == -1 
        issues = issues.where(fixed_version_id: nil) 
      else 
        issues = issues.where(fixed_version_id: milestone_id) 
      end
    end

    issues = issues.where(enterprise_identifier: enterprise_identifier) if enterprise_identifier.present? && ([4,5].include?(pm_issue_type.to_i) || pm_issue_types.present?)

    #pm相关
    # root_id# -1 查一级目录
    issues = if root_id.to_i == -1
               issues.where(root_id: nil)
             elsif root_id.to_i.positive?
               issues.where(root_id: root_id)
             else
               issues
             end

    # pm_issue_type
    issues = issues.where(pm_issue_type: pm_issue_type) if pm_issue_type.present?

    # pm_project_id
    issues = issues.where(pm_project_id: pm_project_id) if pm_project_id.present?
    issues = issues.where(pm_project_id: pm_project_ids.to_s.split(",")) if pm_project_ids.present?

    # pm_sprint_id
    issues = issues.where(pm_sprint_id: pm_sprint_id) if pm_sprint_id.present?

    # assigner_id
    if assigner_id.present?
      if assigner_id.to_i == -1 
        issues = issues.left_joins(:assigners).where(users: {id: nil})
      else 
        issues = issues.joins(:assigners).where(users: {id: assigner_id})
      end
    end

    # status_id
    issues = issues.where(status_id: status_id) if status_id.present? && category != 'closed'

    # priority_id
    issues = issues.where(priority_id: priority_id) if priority_id.present?

    # status_ids 
    issues = issues.where(status_id: status_ids) unless status_ids.blank?

    # pm_issue_types
    issues = issues.where(pm_issue_type: pm_issue_types) unless pm_issue_types.blank?

    # ids
    issues = issues.where(id: ids.to_s.split(",")) if ids.present?

    # exclude_ids
    issues = issues.where.not(id: exclude_ids.to_s.split(",")) if exclude_ids.present?

    if begin_date&.present? || end_date&.present?
      issues = issues.where('issues.created_on between ? and ?', begin_date&.present? ? begin_date.to_time : Time.now.beginning_of_day, end_date&.present? ? end_date.to_time.end_of_day : Time.now.end_of_day)
    end

    if update_begin_date&.present? || update_end_date&.present?
      issues = issues.where('issues.updated_on between ? and ?', update_begin_date&.present? ? update_begin_date.to_time.beginning_of_week : Time.now.beginning_of_week, update_end_date&.present? ? update_end_date.to_time.end_of_week : Time.now.end_of_week)
    end

    # keyword
    issues = issues.ransack(id_or_project_issues_index_eq: keyword).result.or(issues.ransack(subject_or_description_cont: keyword).result) if keyword.present?


    @closed_issues_count = issues.closed.distinct.size
    @opened_issues_count = issues.opened.distinct.size
    @complete_issues_count = issues.closed.distinct.size + issues.where(status_id: 3).distinct.size - issues.where(pm_issue_type: 3, status_id: 3).distinct.size

    case category 
    when 'closed'
      issues = issues.closed
    when 'opened'
      issues = issues.opened
    end
    if only_name.present? 
      scope = issues.select(:id, :subject, :project_issues_index, :updated_on, :created_on)
      scope = scope.reorder("#{sort_by} #{sort_direction}").distinct
    else
      scope = issues.includes(:priority, :issue_status, :user, :show_assigners, :show_issue_tags, :version, :comment_journals)
      scope = if sort_by == 'issue_priorities.position'
                scope.reorder("issue_priorities.position #{sort_direction}, issues.updated_on DESC").distinct
              elsif sort_by == 'assigners'
                scope.with_assigner_info.ordered_by_assigner(sort_direction)
              else
                scope.reorder("#{sort_by} #{sort_direction}").distinct
              end
    end

    @queried_issues = scope
  end

end