require 'net/http'
require 'uri'
require './lib/wordpress_object'
require './lib/downloaded_files'
require 'byebug'

class ProcessUpdateQueueJob
	include Sidekiq::Job

	def perform(type, item)
		wp_object = WordPressObject.new(REDIS)
		downloaded_files = DownloadedFiles.new(CONFIG['storage_path'])

		type = determine_type(type)
		slug = item['slug']
		download_url = get_download_link(type, item)
		filename = File.basename(URI.parse(download_url).path)

		download_and_store_file(downloaded_files, type, slug, filename, download_url)

		item = update_download_links(type, item, slug, filename)
		item = update_core_packages(type, slug, item, downloaded_files) if type == 'core'

		wp_object.store_object(type, slug, item)

		cleanup_old_versions(wp_object, downloaded_files, type, slug)
	end

	private

	def determine_type(type)
		%w[plugin theme core].include?(type) ? type : nil
	end

	def get_download_link(type, item)
		item['download_link'] ||
			(type == 'theme' ? "https://downloads.wordpress.org/theme/#{item["slug"]}.#{item["version"]}.zip" : item.dig("download"))
	end

	def download_file(url, limit = 10)
		raise 'Too many HTTP redirects' if limit == 0

		uri = URI(url)
		response = Net::HTTP.get_response(uri)

		case response
		when Net::HTTPSuccess then
			response.body
		when Net::HTTPRedirection then
			location = response['location']
			download_file(location, limit - 1)
		else
			response.value
		end
	end

	def download_and_store_file(downloaded_files, type, slug, filename, download_url)
		unless downloaded_files.retrieve_file(type, slug, filename)
			file_content = download_file(download_url)
			downloaded_files.store_file(type, slug, filename, file_content)
		end
	end

	def update_download_links(type, item, slug, filename)
		file_server_url = CONFIG['file_server_url']
		item['package'] = "#{file_server_url}/download/#{type}/#{slug}/#{filename}" if type != 'core'
		item['download'] = "#{file_server_url}/download/#{type}/#{slug}/#{filename}" if type == 'core'
		item
	end

	def update_core_packages(type, slug, item, downloaded_files)
		packages = item['packages'] || {}
		packages.each do |key, download_url|
			next unless download_url
			filename = File.basename(URI.parse(download_url).path)
			download_and_store_file(downloaded_files, type, slug, filename, download_url)
			item['packages'][key] = "#{CONFIG['file_server_url']}/download/#{type}/#{slug}/#{filename}"
		end

		item
	end

	def cleanup_old_versions(wp_object, downloaded_files, type, slug)
		max_versions = CONFIG.dig('file_retention', 'max_versions') || 5

		all_versions_before = wp_object.get_object(type, slug)
		return unless all_versions_before && all_versions_before.size > max_versions

		versions_before = all_versions_before.map { |v| v['version'] }

		wp_object.reduce_entries_by_count(type, slug, max_versions)

		all_versions_after = wp_object.get_object(type, slug)
		versions_after = all_versions_after.map { |v| v['version'] }

		removed_versions = versions_before - versions_after

		removed_versions.each do |version|
			downloaded_files.delete_files_for_version(type, slug, version)
		end
	end
end

