# frozen_string_literal: true

require 'zip'
require 'json'
require 'fileutils'
require 'securerandom'
require_relative '../config/database'

# 升级包部署服务
class UpgradePackageDeployer
  MANIFEST_VERSION = '1.0'.freeze

  # 部署升级包
  # @param zip_path [String] 压缩包路径
  # @return [Hash] 部署结果
  def deploy(zip_path)
    extract_dir = nil
    record = nil

    begin
      puts "[DEBUG] 开始部署升级包: #{zip_path}"

      # 1. 验证压缩包
      unless File.exist?(zip_path)
        puts "[DEBUG] 压缩包不存在: #{zip_path}"
        return { success: false, error: '压缩包不存在' }
      end

      # 2. 解压压缩包
      extract_dir = File.join('./tmp/upgrade_deploy', SecureRandom.uuid)
      FileUtils.mkdir_p(extract_dir)
      puts "[DEBUG] 解压到: #{extract_dir}"

      extract_package(zip_path, extract_dir)

      # 3. 读取manifest
      manifest_path = File.join(extract_dir, 'manifest.json')
      puts "[DEBUG] manifest路径: #{manifest_path}, 存在: #{File.exist?(manifest_path)}"

      unless File.exist?(manifest_path)
        puts "[DEBUG] 列出解压目录内容: #{Dir.children(extract_dir)}"
        return { success: false, error: 'manifest.json 不存在' }
      end

      manifest_content = File.read(manifest_path)
      puts "[DEBUG] manifest内容: #{manifest_content}"
      manifest = JSON.parse(manifest_content)

      unless validate_manifest(manifest)
        puts "[DEBUG] manifest验证失败"
        return { success: false, error: '无效的manifest格式' }
      end

      puts "[DEBUG] manifest验证通过: #{manifest['name']} v#{manifest['version']}"

      # 4. 创建升级记录
      record_id = SecureRandom.uuid
      puts "[DEBUG] 创建记录, id=#{record_id}"
      record = UpgradeRecord.insert(
        id: record_id,
        package_name: manifest['name'] || 'unknown',
        package_version: manifest['version'] || 'unknown',
        status: 'deploying',
        started_at: Time.now
      )
      record = UpgradeRecord[record_id]
      puts "[DEBUG] 记录创建成功: #{record.inspect}"

      # 5. 部署文件
      file_results = deploy_files(manifest['files'], extract_dir)

      # 6. 更新记录状态
      success_count = file_results.count { |r| r[:status] == 'success' }
      total_count = file_results.size

      if success_count == total_count
        record.complete_deployment!(success: true, result: {
          message: "部署成功，共 #{total_count} 个文件",
          success_count: success_count,
          total_count: total_count
        }, file_results: file_results)
      elsif success_count > 0
        record.complete_deployment!(success: false, result: {
          message: "部分成功，成功 #{success_count}/#{total_count} 个文件",
          success_count: success_count,
          total_count: total_count
        }, file_results: file_results)
      else
        record.complete_deployment!(success: false, result: {
          message: '部署失败',
          success_count: success_count,
          total_count: total_count
        }, file_results: file_results)
      end

      {
        success: record.status == 'success',
        record: record.to_api_hash,
        file_results: file_results
      }
    rescue StandardError => e
      LogService.error("部署升级包失败: #{e.message}") if defined?(LogService)

      record&.complete_deployment!(success: false, result: {
        message: "部署异常: #{e.message}"
      })

      { success: false, error: e.message }
    ensure
      # 清理解压目录
      FileUtils.rm_rf(extract_dir) if extract_dir && Dir.exist?(extract_dir)
    end
  end

  private

  # 验证manifest格式
  def validate_manifest(manifest)
    return false unless manifest.is_a?(Hash)
    return false unless manifest['version']&.to_s&.start_with?('1.0')
    return false unless manifest['files'].is_a?(Array)
    true
  end

  # 解压压缩包
  def extract_package(zip_path, extract_dir)
    Zip::File.open(zip_path) do |zipfile|
      zipfile.each do |entry|
        dest_path = File.join(extract_dir, entry.name)
        dest_dir = File.dirname(dest_path)

        FileUtils.mkdir_p(dest_dir)
        zipfile.extract(entry, dest_path)
      end
    end
  end

  # 部署文件
  def deploy_files(files, extract_dir)
    results = []

    files.each do |file_info|
      source_relative = file_info['source']
      target_path = file_info['target']
      description = file_info['description'] || ''

      source_path = File.join(extract_dir, source_relative)

      result = {
        source: source_relative,
        target: target_path,
        description: description,
        status: 'failed',
        error: nil
      }

      begin
        if File.exist?(source_path)
          # 备份原文件（如果存在）
          if File.exist?(target_path)
            backup_path = "#{target_path}.backup.#{Time.now.strftime('%Y%m%d%H%M%S')}"
            FileUtils.rm_rf(backup_path)
            if File.directory?(target_path)
              FileUtils.mv(target_path, backup_path)
            else
              FileUtils.mv(target_path, backup_path)
            end
            result[:backup] = backup_path
          end

          # 复制文件或目录
          if File.directory?(source_path)
            FileUtils.cp_r(source_path, target_path)
          else
            FileUtils.cp(source_path, target_path)
          end
          result[:status] = 'success'
        else
          result[:error] = '源文件不存在'
        end
      rescue StandardError => e
        result[:error] = e.message
      end

      results << result
    end

    results
  end
end
