class Ci::PipelinesController < Ci::BaseController

  before_action :require_login, only: %i[list create content]
  skip_before_action :connect_to_ci_db, except: %i[list create destroy content]
  before_action :load_project, only: %i[create content]
  before_action :load_repo, only: %i[create content]

  # ======流水线相关接口========== #
  def list
    @result = Array.new
    list = Ci::Pipeline.where('identifier=? and owner=?', params[:identifier], params[:owner])
    # 查询build状态
    list.collect do |pipeline|
      pipeline.last_build_time = nil
      repo = load_repo_by_repo_slug("#{pipeline.owner}/#{pipeline.identifier}")
      if repo
        build = repo.builds.order("build_created desc").find_by(build_target: pipeline.branch)
        if build
          pipeline.pipeline_status = build.build_status
          pipeline.last_build_time = Time.at(build.build_created)
        end
      end
      @result.push(pipeline)
    end
    @total_count = @result.size
    @pipelines = paginate @result
  end

  def create
    ActiveRecord::Base.transaction do
      size = Ci::Pipeline.where('branch=? and identifier=? and owner=?', params[:branch], params[:repo], params[:owner]).size
      if size > 0
        tip_exception("#{params[:branch]}分支已经存在流水线！")
        return
      end
      pipeline = Ci::Pipeline.new(pipeline_name: params[:pipeline_name], file_name: params[:file_name],owner: params[:owner],
                                  login: current_user.login, identifier: params[:repo], branch: params[:branch], event: params[:event])
      pipeline.save!

      # 默认创建四个初始阶段
      init_stages = Ci::PipelineStage::INIT_STAGES
      index = 1
      init_stages.each do |type, name|
        pipeline.pipeline_stages.build(
          stage_name: name,
          stage_type: type,
          show_index: index
        ).save!
        index += 1
      end
      create_pipeline_file(pipeline)
      create_ci_repo(pipeline)
      render_ok({id: pipeline.id})
    end
  rescue Exception => ex
    tip_exception(ex.message)
  end

  # 在代码库创建文件
  def create_pipeline_file(pipeline)
    sha = get_pipeline_file_sha(pipeline.file_name, pipeline.branch)
    if sha
      logger.info "#{pipeline.file_name}已存在"
    else
      interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
      if interactor.success?
        logger.info "#{pipeline.file_name}创建成功"
      end
    end
  end

  # 在drone数据库repo表新增一条repo记录
  def create_ci_repo(pipeline)
    if pipeline.branch != 'master'
      create_params = {
        repo_user_id: @ci_user.user_id,
        repo_namespace: @project.owner.login,
        repo_name: @project.identifier,
        repo_slug: "#{@project.owner.login}/#{@project.identifier}-" + pipeline.id.to_s,
        repo_clone_url: @project.repository.url,
        repo_branch: pipeline.branch,
        repo_config: pipeline.file_name
      }
      Rails.logger.info("########create_params===#{create_params.to_json}")
      repo = Ci::Repo.create_repo(create_params)
      repo
    end
    nil
  end

  def get_pipeline_file_sha(file_name, branch)
    file_path_uri = URI.parse(file_name)
    interactor = Repositories::EntriesInteractor.call(@project.owner, @project.identifier, file_path_uri, ref: branch || 'master')
    if interactor.success?
      file = interactor.result
      file['sha']
    end
  end

  def content_params
    {
      filepath: params[:file_name],
      branch: params[:branch],
      new_branch: params[:new_branch],
      content: "#pipeline \n",
      message: 'create pipeline',
      committer: {
        email: current_user.mail,
        name: current_user.login
      },
      identifier: params[:repo]
    }
  end

  def update
    pipeline = Ci::Pipeline.find(params[:id])
    if pipeline
      pipeline.update!(pipeline_name: params[:pipeline_name],branch: params[:branch], event: params[:event])
    end
    render_ok
  rescue Exception => ex
    tip_exception(ex.message)
  end

  def destroy
    pipeline = Ci::Pipeline.find(params[:id])
    if pipeline
      repo = load_repo_by_repo_slug("#{pipeline.login}/#{pipeline.identifier}-" + pipeline.id.to_s)
      if repo
        repo.destroy!
      end
      pipeline.destroy!
    end
    render_ok
  rescue Exception => ex
    tip_exception(ex.message)
  end

  def content
    @yaml = "\n"
    pipeline = Ci::Pipeline.find(params[:id])
    stages = pipeline.pipeline_stages
    if stages && !stages.empty?
      init_step = stages.first.pipeline_stage_steps.first
      @yaml += init_step.content + "\n" + "steps:\n"
      stages = stages.slice(1, stages.size - 1)
      unless stages.empty?
        stages.each do |stage|
          steps = stage.pipeline_stage_steps
          next unless steps && !steps.empty?
          steps.each do |step|
            @yaml += step.content + "\n"
          end
        end
      end
    end
    @sha = get_pipeline_file_sha(pipeline.file_name, pipeline.branch)
    trigger = ''
    trigger += "  branch:\r\n  - #{pipeline.branch}\r\n" unless pipeline.branch.blank?
    unless pipeline.event.blank?
      trigger += "  event:\r\n"
      pipeline.event.split(',').each { |event| trigger += "  - #{event}\r\n"}
    end
    @yaml += "trigger:\r\n" + trigger unless trigger.blank?
    @branch = pipeline.branch
  end

  # =========阶段相关接口========= #
  def stages
    pipeline_id = params[:id]
    @pipeline_name = Ci::Pipeline.find(pipeline_id).pipeline_name
    @pipeline_stages = Ci::PipelineStage.where('pipeline_id=?', pipeline_id).order('show_index asc')
  end

  def create_stage
    ActiveRecord::Base.transaction do
      # 修改stage排序
      update_stage_index(params[:id], params[:show_index], 1)
      pipeline_stage = Ci::PipelineStage.new(stage_name: params[:stage_name],
                                             stage_type: params[:stage_type].blank? ? 'customize' : params[:stage_type],
                                             pipeline_id: params[:id], show_index: params[:show_index])
      pipeline_stage.save!
      render_ok
    end
  rescue Exception => ex
    tip_exception(ex.message)
  end

  def update_stage
    pipeline_stage = Ci::PipelineStage.find(params[:stage_id])
    if pipeline_stage
      pipeline_stage.update!(stage_name: params[:stage_name])
    end
    render_ok
  rescue Exception => ex
    tip_exception(ex.message)
  end

  def delete_stage
    ActiveRecord::Base.transaction do
      update_stage_index(params[:id], params[:show_index].to_i, -1)
      pipeline_stage = Ci::PipelineStage.find(params[:stage_id])
      if pipeline_stage
        pipeline_stage.destroy!
      end
      render_ok
    end
  rescue Exception => ex
    tip_exception(ex.message)
  end

  def update_stage_index(pipeline_id, show_index, diff)
    stages = Ci::Pipeline.find(pipeline_id).pipeline_stages
    stages.each do |stage|
      if stage.show_index >= show_index
        stage.update!(show_index: stage.show_index + diff)
      end
    end
  end

  # ========步骤相关接口========= #
  def steps
    @stage_type = Ci::PipelineStage.find(params[:stage_id]).stage_type
    @pipeline_stage_steps = Ci::PipelineStageStep.where('stage_id=?', params[:stage_id]).order('show_index asc')
  end

  def stage_step
    ActiveRecord::Base.transaction do
      steps = params[:steps]
      unless steps.empty?
        steps.each do |step|
          unless step[:template_id]
            tip_exception('请选择模板！')
            return
          end
          if !step[:id]
            step = Ci::PipelineStageStep.new(step_name: step[:step_name], stage_id: params[:stage_id],
                                             template_id: step[:template_id], content: step[:content], show_index: step[:show_index])
            step.save!
          else
            pipeline_stage_step = Ci::PipelineStageStep.find(step[:id])
            pipeline_stage_step.update(step_name: step[:step_name], content: step[:content],
                                       show_index: step[:show_index], template_id: step[:template_id])
          end
        end
      end
      render_ok
    end
  rescue Exception => ex
    tip_exception(ex.message)
  end

  def create_stage_step
    ActiveRecord::Base.transaction do
      steps = params[:steps]
      unless steps.empty?
        steps.each do |step|
          step = Ci::PipelineStageStep.new(step_name: step[:step_name], stage_id: params[:stage_id],
                                           template_id: step[:template_id], content: step[:content], show_index: step[:show_index])
          step.save!
        end
      end
      render_ok
    end
  rescue Exception => ex
    tip_exception(ex.message)
  end

  def update_stage_step
    ActiveRecord::Base.transaction do
      steps = params[:steps]
      unless steps.empty?
        steps.each do |step|
          pipeline_stage_step = Ci::PipelineStageStep.find(step[:id])
          if pipeline_stage_step
            pipeline_stage_step.update(step_name: step[:step_name], content: step[:content], template_id: step[:template_id])
          end
        end
      end
      render_ok
    end
  rescue Exception => ex
    tip_exception(ex.message)
  end

  def delete_stage_step
    pipeline_stage_step = Ci::PipelineStageStep.find(params[:step_id])
    if pipeline_stage_step
      pipeline_stage_step.destroy!
    end
    render_ok
  rescue Exception => ex
    tip_exception(ex.message)
  end
end
