# frozen_string_literal: true

def maintenance!(enable: true)
  execute :drush, 'state:set', 'system.maintenance_mode', enable.to_s.upcase
end

def composer_auth
  compjson = File.expand_path('../../../composer.json', File.dirname(__FILE__))
  composer = JSON.parse File.read(compjson)

  urls = if composer['repositories'].is_a?(Hash)
           composer['repositories'].collect { |_k, v| v['url'] }
         else
           composer['repositories'].collect { |e| e['url'] }
         end

  urls.each do |u|
    next unless u =~ /oauth2:/

    require 'uri'
    url = ::URI.parse u
    if url.user && url.password
      execute :composer, 'config', '--global', "http-basic.#{url.host}", url.user, url.password
    end
  end
end

def drupal_installed?
  test :drush, 'sql:query', '"SELECT 1 FROM key_value LIMIT 1"'
end

def cache_clear
  execute :drush, 'cache:rebuild'
end

def install_site
  info 'Drupal not yet installed — running site:install with profile, then config:import...'
  execute :drush, 'site:install', 'macroweb_drupal_skeleton',
          "--root=#{release_path.join(fetch(:drupal_root))}", '--locale=en',
          '--account-name=diadmin', '--account-mail=info@macroweb.hu', '--site-mail=info@macroweb.hu', '-y'
  execute :drush, 'config:set', '-y', 'system.site', 'uuid', site_uuid
  languages.each do |lang|
    execute :drush, 'config:set', '-y', "language.entity.#{lang}", 'uuid', lang_uuid(lang)
  end
  execute :drush, 'config:import', "--root=#{release_path.join(fetch(:drupal_root))}", '-y'
  execute :drush, 'cache:rebuild'
end

def update_db
  maintenance!
  execute :drush, 'updatedb', '-y', '--cache-clear' # , '--post-updates'
  cache_clear
end

def site_uuid
  siteyml = File.expand_path('../../../config/sync/default/system.site.yml', File.dirname(__FILE__))
  if File.exist? siteyml
    YAML.load_file(siteyml)['uuid']
  else
    SecureRandom.uuid
  end
end

def lang_uuid(lang)
  langyml = File.expand_path("../../../config/sync/default/language.entity.#{lang}.yml", File.dirname(__FILE__))

  if File.exist? langyml
    YAML.load_file(langyml)['uuid']
  else
    SecureRandom.uuid
  end
end

def languages
  langymls = Dir.glob File.expand_path('../../../config/sync/default/language.entity.*.yml', File.dirname(__FILE__))
  langs = langymls.map do |f|
    File.basename(f).sub('language.entity.', '').sub(/\.yml$/, '').to_sym
  end
  langs.find_all { |lang| !%i[zxx und en].include?(lang) }
end

namespace :load do
  task :defaults do
    set :drupal_root, 'web'
  end
end

namespace :composer do
  task :install do
    on roles(:app) do
      within release_path do
        composer_auth
        stage = fetch(:stage).to_s
        devel_enabled = %w[demo dev].include?(stage) ? '--dev' : '--no-dev'
        execute :composer, 'install', '--no-progress', '--no-interaction', '--prefer-dist', devel_enabled
      end
    end
  end
end

# rubocop:disable Metrics/BlockLength
namespace :drupal do
  task :set_paths do
    SSHKit.config.command_map[:drupal] =
      "#{fetch(:php_path, '/usr/bin/php')} -d display_errors=1 -d memory_limit=-1 #{shared_path}/vendor/bin/drupal"
    # For Drupal 11 / Drush 13: vendor/bin/drush is a shell wrapper, not PHP
    # Execute it directly without PHP interpreter to avoid displaying wrapper script content
    SSHKit.config.command_map[:drush] = "#{shared_path}/vendor/bin/drush"
    SSHKit.config.command_map[:composer] = lambda {
      "#{fetch(:php_path, '/usr/bin/php')} -d memory_limit=-1 -d allow_url_fopen=1 #{release_path}/composer.phar"
    }
  end

  namespace :site do
    task :backup do
      # TODO: Rewrite me when https://www.drupal.org/project/backup_migrate/issues/2968766 closed
      on roles(:app) do
        within current_path.join(fetch(:drupal_root)) do
          execute :drush, 'eval', %{'backup_migrate_perform_backup("default_db", "private_files", []);'}
        end
      end
    end

    desc 'Setting up a brand new drupal instance based on the configs we have'
    task :setup do
      invoke 'deploy:check'
      invoke 'drupal:set_paths'
      invoke 'deploy:updating'
      invoke 'composer:install'

      on roles(:app) do
        within release_path.join(fetch(:drupal_root)) do
          execute :drush, 'site:install', "--root=#{release_path.join(fetch(:drupal_root))}", '--locale=en',
                  '--account-name=diadmin', '--account-mail=info@macroweb.hu', '--site-mail=info@macroweb.hu', '-y',
                  '--existing-config'
          execute :drush, 'config:set', '-y', 'system.site', 'uuid', site_uuid
          languages.each do |lang|
            execute :drush, 'config:set', '-y', "language.entity.#{lang}", 'uuid', lang_uuid(lang)
          end
          execute :drush, 'config:import', "--root=#{release_path.join(fetch(:drupal_root))}", '-y'
          # languages.each do |lang|
          #   execute :drush, 'locale:import', "--root=#{release_path.join(fetch(:drupal_root))}", lang,
          #           release_path.join("translations/#{lang}.po"), '--override=all',
          #           '--type=customized'
          # end
        end
      end

      invoke 'deploy:publishing'
      invoke 'deploy:published'
      invoke 'deploy:finishing'
      invoke 'deploy:finished'
    end

    task :offline do
      on roles(:app) do
        if test("[ -d #{current_path} -a -f #{shared_path.join('vendor/bin/drupal')} ]")
          within current_path.join(fetch(:drupal_root)) do
            # execute :drupal, 'site:maintenance', 'on'
            maintenance!
          end
        end
      end
    end

    task :online do
      on roles(:app) do
        within release_path.join(fetch(:drupal_root)) do
          # execute :drupal, 'site:maintenance', 'off'
          maintenance! enable: false
        end
      end
    end
  end

  task :update do
    on roles(:app) do
      within release_path.join(fetch(:drupal_root)) do
        unless drupal_installed?
          install_site
          next
        end

        update_db
        maintenance!
        execute :drush, 'cache:rebuild'
        # Import config after db update but before locale operations
        info 'Importing configuration changes...'
        execute :drush, 'config:set', '-y', 'system.site', 'uuid', site_uuid
        # Config import may trigger locale batch operations that can fail - continue deploy even if they fail
        begin
          execute :drush, 'config:import', '-y', '--verbose'
        rescue StandardError => e
          # Config import can fail due to locale translation download errors in batch operations
          # This is non-critical - the config itself is usually imported successfully before the batch fails
          warn "Config import command failed (possibly due to locale batch operations): #{e.message}"
          warn 'Continuing deploy - configuration may have been imported successfully before batch failure'
        end
        execute :drush, 'cache:rebuild'
        # Locale operations are non-critical - continue deploy even if they fail
        #begin
          #execute :drush, 'locale:check'
          #execute :drush, 'locale:update'
          # átmozgatva a 187. sorba. Az előző drush locale:update behal az address hibája miatt, ezért a lokális fordításokat megpróbáljuk később
          # execute :drush, 'locale:import:all', "--root=#{release_path.join(fetch(:drupal_root))}",
          #         release_path.join('translations'), '--override=all', '--type=customized'
        #rescue StandardError => e
        #  warn "Locale operations failed (non-critical): #{e.message}"
        #end

        # execute :drush, 'locale:rebuild'
        #execute :drush, 'locale:import:all', "--root=#{release_path.join(fetch(:drupal_root))}",
        #        release_path.join("translations"), '--override=all', '--type=customized', '--yes'
        # Case: https://atrium.macroweb.hu/virradat/node/38923#comment-194653
        execute :drush, 'config:import', "--root=#{release_path.join(fetch(:drupal_root))}", '-y'
        execute :drush, 'colorbox-dompurify'
        maintenance!
        maintenance! enable: false
      end
    end
  end

  namespace :cache do
    task :clear do
      on roles(:app) do
        within release_path.join(fetch(:drupal_root)) do
          # execute :drupal, 'cache:rebuild'
          cache_clear
        end
      end
    end
  end

  namespace :symlink do
    task :htdocs do
      on roles(:app) do
        execute :rm, '-f', deploy_path.join('htdocs')
        execute :ln, '-sf', release_path, deploy_path.join('htdocs')
      end
    end

    task :htaccess do
      on roles(:app) do
        execute :rm, '-f', release_path.join('web/.htaccess')
        execute :ln, '-sf', release_path.join('htaccess.txt'), release_path.join('web/.htaccess')
      end
    end
  end

  namespace :cpanel do
    desc 'Remove cPanel-created current directory before first deploy'
    task :cleanup_current do
      on roles(:app) do
        current = deploy_path.join('current')
        # Only act if current is a real directory (not a symlink)
        next if test("[ -L #{current} ]") || !test("[ -d #{current} ]")

        # Safety check: only remove if it matches cPanel's default structure (web/.htaccess only)
        if test("[ -d #{current}/web ]") &&
           test("[ $(find #{current}/web -maxdepth 1 -not -name web -not -name .htaccess | wc -l) -eq 0 ]")
          info 'Removing cPanel-created current directory...'
          execute :rm, '-rf', current
        else
          warn "#{current} is a real directory but does not match cPanel default structure — skipping removal"
        end
      end
    end
  end

  namespace :cleanup do
    task :unharden do
      on roles(:app) do
        real_current = capture(:readlink, current_path)
        dirs = capture(:ls, '-xd', releases_path.join('*/web/sites/default')).split.find_all do |dir|
          !dir.match(real_current)
        end
        dirs.each do |default_dir|
          execute :chmod, 'u+w', default_dir
        end
      end
    end

    task :harden do
      on roles(:app) do
        real_current = capture(:readlink, current_path)
        dirs = capture(:ls, '-xd', releases_path.join('*/web/sites/default')).split.find_all do |dir|
          !dir.match(real_current)
        end
        dirs.each do |default_dir|
          execute :chmod, 'u-w', default_dir
        end
      end
    end
  end
end
# rubocop:enable Metrics/BlockLength

before 'deploy:check', 'drupal:cpanel:cleanup_current'
after 'deploy:updating', 'drupal:set_paths'
before 'deploy:updated', 'drupal:site:offline'
after 'deploy:updated', 'composer:install'
# before 'deploy:updated', 'drupal:site:backup'
after 'deploy:updated', 'drupal:update'
after 'deploy:published', 'drupal:site:online'
after 'deploy:published', 'drupal:cache:clear'
before 'deploy:cleanup', 'drupal:cleanup:unharden'
after 'deploy:cleanup', 'drupal:cleanup:harden'
