require 'find'
require 'fileutils'

source = ENV['PWD'] || Dir.pwd
tasks_root = File.join(source, 'tasks')
destination = node['git']['dir']['workspace']
working = "#{destination}/workdir"

Common.directories(self, [destination, working], recreate: true)

(tasks = Dir.glob(File.join(tasks_root, '*')).select { |d| File.directory?(d) }.map { |p| p.sub(source, '.') }).each do |task_dir|

  name_repo = File.basename(task_dir)
  path_source = File.expand_path(task_dir.to_s, source.to_s)
  path_working = "#{working}/#{name_repo}"
  path_destination = File.expand_path(name_repo, destination)

  ruby_block "task_repo_exists_#{name_repo}" do
    only_if { Logs.true("[task: #{name_repo}] exist") }
    block do
      uri = "#{node['git']['api']['endpoint']}/repos/#{node['git']['org']['tasks']}/#{name_repo}"
      node.run_state["#{name_repo}_repo_exists"] = Utils.request(uri, user: Env.get(self, 'login'), pass: Env.get(self, 'password')).code.to_i != 404
    end
  end

  execute "task_snapshot_create_#{name_repo}" do
    command <<-EOH
      if git ls-remote ssh://#{node['app']['user']}@#{node['git']['host']['ssh']}/#{node['git']['org']['tasks']}/#{name_repo}.git HEAD | grep -q .; then
        git clone --recurse-submodules ssh://#{node['app']['user']}@#{node['git']['host']['ssh']}/#{node['git']['org']['tasks']}/#{name_repo}.git #{path_working}
        cd #{path_working} && find . -type d -name .git -exec rm -rf {} +
      else
        mkdir -p #{path_working}
      fi
    EOH
    user node['app']['user']
    only_if { node.run_state["#{name_repo}_repo_exists"] }
  end

  ruby_block "task_repo_reset_#{name_repo}" do block do
      Utils.request("#{node['git']['api']['endpoint']}/repos/#{node['git']['org']['tasks']}/#{name_repo}",
        log: "Delete #{name_repo}", method: Net::HTTP::Delete, expect: [204, 404],
        user: Env.get(self, 'login'), pass: Env.get(self, 'password'))
    end
    only_if { node.run_state["#{name_repo}_repo_exists"] }
  end

  ruby_block "task_repo_create_#{name_repo}" do
    only_if { Logs.true("[task: #{name_repo}] create repo") }
    block do
      Utils.request("#{node['git']['api']['endpoint']}/admin/users/#{node['git']['org']['tasks']}/repos",
        method: Net::HTTP::Post, user: Env.get(self, 'login'), pass: Env.get(self, 'password'), headers: Constants::HEADER_JSON,
        body: { name: name_repo, private: false, auto_init: false, default_branch: 'main' })
      Utils.request("#{node.dig('git','api','endpoint')}/repos/#{node['git']['org']['tasks']}/#{name_repo}",
        method: Net::HTTP::Patch, user: Env.get(self, 'login'), pass: Env.get(self, 'password'), headers: Constants::HEADER_JSON,
        body: { has_issues: false, has_wiki: false, has_projects: false, has_packages: false, has_releases: false } )
    end
  end

  execute "task_repo_init_#{name_repo}" do
    command <<-EOH
      mkdir -p #{path_destination} && cd #{path_destination} && git init -b main
    EOH
    user node['app']['user']
  end

  template "#{path_destination}/.git/config" do
    source 'repo_config.erb'
    owner node['app']['user']
    group node['app']['group']
    mode '0644'
    variables(repo: name_repo, config: node['app']['config'], org: node['git']['org']['tasks'], ssh: node['git']['host']['ssh'])
    only_if { ::File.directory?("#{path_destination}/.git") }
  end

  ruby_block "task_files_sync_#{name_repo}" do
    block do
      Find.find(path_source) do |p|
        next if p =~ /(^|\/)\.git(\/|$)/
        rel = p.sub(/^#{Regexp.escape(path_source)}\/?/, '')
        next if rel.empty?
        dst = File.join(path_destination, rel)
        if File.directory?(p)
          FileUtils.mkdir_p(dst)
        else
          FileUtils.mkdir_p(File.dirname(dst))
          FileUtils.cp(p, dst, verbose: true)
        end
      end
      FileUtils.mkdir_p(File.join(path_destination, '.gitea', 'workflows'))
      FileUtils.chown_R(node['app']['user'], node['app']['group'], path_destination)
    end
  end

  ruby_block "task_script_find_#{name_repo}" do
    block do
      d = File.join(path_destination, 'default.rb')
      m = File.join(path_destination, 'main.rb')
      g = Dir.glob(File.join(path_destination, '*.rb')).sort
      s = if File.file?(d); 'default.rb'
        elsif File.file?(m); 'main.rb'
        elsif g.any?; File.basename(g.first)
        end
      node.run_state["#{name_repo}_script"] = s
    end
  end

  ruby_block "task_script_directive_#{name_repo}" do
    block do
      p = File.join(path_destination, node.run_state["#{name_repo}_script"])
      c = File.read(p).dup.force_encoding('UTF-8')
      m = c.lines.map { |ln| ln[/^\s*#\s*!+\s*cron\s+["']([^"']+)["']/i, 1] }.compact.first
      node.run_state["#{name_repo}_cron"] = (m || '').strip
    end
  end

  template "#{path_destination}/.gitea/workflows/task.yml" do
    source 'task_pipeline.yml.erb'
    owner node['app']['user']
    group node['app']['group']
    mode '0644'
    variables lazy { {
      org: node['git']['org']['tasks'], repo: name_repo,
      script: node.run_state["#{name_repo}_script"],
      cron: node.run_state["#{name_repo}_cron"] } }
  end

  execute "task_repo_base_commit_#{name_repo}" do
    command <<-EOH
      git add --all
      git commit --allow-empty -m "init [skip ci]" || true
      git push -u origin main
    EOH
    cwd path_destination
    user node['app']['user']
  end

  execute "task_repo_touch_workflow_#{name_repo}" do
    command <<-EOH
      WORKFLOW_FILE="#{path_destination}/.gitea/workflows/task.yml"
      if [ -f "$WORKFLOW_FILE" ]; then
        touch "$WORKFLOW_FILE" && git add "$WORKFLOW_FILE"
        git commit --allow-empty -m "scheduled workflow"
        git push origin main || true
      fi
    EOH
    cwd  path_destination
    user node['app']['user']
    only_if { node.run_state["#{name_repo}_cron"].present? }
    not_if  { ['127.0.0.1', 'localhost', '::1'].include?(Env.get(self, 'host')) }
  end

  directory path_destination do
    action :delete
    recursive true
    only_if { ::Dir.exist?(path_destination) }
  end

end