# frozen_string_literal: true

require 'securerandom'
require 'sequel'
require 'json'
require 'time'
require_relative '../config/database'

# 确保数据库连接已建立并设置全局Sequel模型数据库
Database.connection

# 本地任务模型
class LocalTask < Sequel::Model(:local_tasks)
  # Sequel模型插件
  plugin :timestamps, update_on_create: true
  plugin :validation_helpers
  plugin :json_serializer
  plugin :serialization

  # JSON序列化字段
  serialize_attributes :json, :task_definition

  # 关联
  one_to_many :executions, class: :LocalTaskExecution, key: :task_id

  # 验证
  def validate
    super
  end

  # 获取最新的执行记录
  def latest_execution
    executions_dataset.order(Sequel.desc(:created_at)).first
  end

  # 获取当前状态（来自最新执行记录）
  def current_status
    latest_execution&.status || 'pending'
  end

  def current_status_text
    latest_execution&.status_text || '待执行'
  end

  def current_progress
    latest_execution&.progress || 0
  end

  # 创建新的执行记录
  def create_new_execution!
    LocalTaskExecution.create_for_task(id)
  end

  # 重置任务：清除未完成的执行记录并创建新的执行记录
  def reset!
    # 删除所有未完成的执行记录
    executions_dataset.where(status: ['pending', 'running']).destroy
    # 创建新的执行记录
    create_new_execution!
  end

  # 从云端任务定义创建本地任务
  def self.create_from_cloud_definition(cloud_task_definition)
    LogService.info("[LocalTask] 创建本地任务，输入: #{cloud_task_definition.inspect[0..1500]}")

    task = new
    task.id = SecureRandom.uuid
    task.name = cloud_task_definition[:name] || cloud_task_definition['name'] || "任务 #{Time.now.strftime('%Y%m%d_%H%M%S')}"
    task.description = cloud_task_definition[:description] || cloud_task_definition['description']

    # 保存完整的任务定义
    task.task_definition = cloud_task_definition[:definition] || cloud_task_definition['definition'] || cloud_task_definition

    LogService.info("[LocalTask] 保存的 task_definition: #{task.task_definition.inspect[0..1500]}")

    # 从任务定义中解析设备数量
    task.device_count = calculate_device_count(task.task_definition)
    LogService.info("[LocalTask] 计算出的设备数量: #{task.device_count}")

    task.save

    LogService.info("[LocalTask] 任务已保存，ID: #{task.id}")

    # 同时创建初始执行记录
    task.create_new_execution!

    LogService.info("[LocalTask] 初始执行记录已创建")

    task
  end

  # 计算设备数量（使用与LocalTaskExecution相同的逻辑）
  def self.calculate_device_count(definition)
    return 0 unless definition && definition.is_a?(Hash)

    LogService.info("[LocalTask] calculate_device_count 输入: #{definition.inspect[0..1000]}")

    # 支持多种格式
    # 1. 直接有 devices 字段
    devices = definition[:devices] || definition['devices']
    return devices.length if devices && devices.is_a?(Array)

    # 2. 从 task_json 中解析（分组格式）
    task_json = definition[:task_json] || definition['task_json'] || {}
    return 0 unless task_json.is_a?(Hash)

    LogService.info("[LocalTask] calculate_device_count task_json: #{task_json.inspect[0..1000]}")

    # 检查 task_json 是否直接包含 devices
    if task_json.key?('devices') || task_json.key?(:devices)
      devices = task_json['devices'] || task_json[:devices] || []
      return devices.length if devices.is_a?(Array)
    end

    # 使用与LocalTaskExecution#convert相同的逻辑（分组格式）
    device_list = []
    task_json.each_value do |group|
      next unless group.is_a?(Hash)
      devs = group['devs'] || group[:devs] || []
      device_list.concat(devs)
    end

    count = device_list.uniq { |d| d['id'] || d[:id] }.length
    LogService.info("[LocalTask] calculate_device_count 结果: #{count}")
    count
  end

  # === 未选择设备ID处理 ===
  def unselected_device_ids_array
    return [] unless unselected_device_ids && !unselected_device_ids.empty?
    unselected_device_ids.split(',').map(&:strip).reject(&:empty?)
  end

  def unselected_device_ids_array=(ids)
    self.unselected_device_ids = ids.is_a?(Array) ? ids.join(',') : ids.to_s
  end

  def device_selected?(device_id)
    !unselected_device_ids_array.include?(device_id.to_s)
  end

  # === 未选择脚本ID处理 ===
  def unselected_script_ids_array
    return [] unless unselected_script_ids && !unselected_script_ids.empty?
    unselected_script_ids.split(',').map(&:strip).reject(&:empty?)
  end

  def unselected_script_ids_array=(ids)
    self.unselected_script_ids = ids.is_a?(Array) ? ids.join(',') : ids.to_s
  end

  def script_selected?(script_id)
    !unselected_script_ids_array.include?(script_id.to_s)
  end

  # 从execution_units获取设备数量
  def device_count_from_units(units)
    (units && units.is_a?(Hash)) ? units.size : device_count
  end

  # 简单合并：用 mem_units 的状态更新 full_units（保留 full_units 的 log_file_path）
  def merge_mem_state(full_units, mem_units)
    return full_units unless mem_units && mem_units.is_a?(Hash)

    # 复制 full_units
    result = JSON.parse(full_units.to_json) rescue Marshal.load(Marshal.dump(full_units)) rescue full_units.dup

    mem_units.each do |dev_id, mem_unit|
      # 查找设备
      dev_key = result.key?(dev_id) ? dev_id : dev_id.to_s
      next unless result[dev_key] && mem_unit.is_a?(Hash)

      mu = mem_unit.stringify_keys rescue mem_unit
      next unless mu.is_a?(Hash)

      # 更新设备状态
      result[dev_key]['status'] = mu['status'] if mu['status']

      # 更新脚本
      mem_scripts = mu['scripts'] || {}
      next unless mem_scripts.is_a?(Hash)

      res_scripts = result[dev_key]['scripts'] || {}
      mem_scripts.each do |script_id, mem_script|
        script_key = res_scripts.key?(script_id) ? script_id : script_id.to_s
        next unless res_scripts[script_key] && mem_script.is_a?(Hash)

        ms = mem_script.stringify_keys rescue mem_script
        next unless ms.is_a?(Hash)

        # 更新动态字段
        %w[status started_at completed_at conclusion output error].each do |k|
          res_scripts[script_key][k] = ms[k] if ms[k]
        end
      end
    end

    result
  end

  # 将 execution_units Hash 转换为前端需要的数组格式
  def convert_execution_units_to_array(units_hash)
    return [] unless units_hash && units_hash.is_a?(Hash)

    status_text_map = {
      'pending' => '待执行',
      'running' => '执行中',
      'completed' => '已完成',
      'failed' => '失败',
      'cancelled' => '已取消'
    }

    units_hash.map do |device_id, unit|
      # 兼容符号键和字符串键
      unit = unit.transform_keys(&:to_s)
      scripts = unit['scripts'] || {}

      # 将 scripts hash 转为数组
      scripts_array = scripts.map do |script_id, script|
        script = script.transform_keys(&:to_s) if script.is_a?(Hash)
        script
      end.compact

      # 计算设备级别的状态和进度
      device_status = calculate_device_status(scripts_array)
      device_progress = calculate_device_progress(scripts_array)
      current_script = find_current_script(scripts_array)

      {
        id: unit['id'] || device_id,
        device_id: device_id,
        device_name: unit['name'] || unit['device_name'],
        name: unit['name'] || unit['device_name'],
        device_model: unit['device_model'],
        device_ip: unit['device_ip'],
        description: unit['description'],
        status: device_status,
        status_text: status_text_map[device_status] || device_status,
        progress: device_progress,
        current_script: current_script,
        scripts: scripts_array,
        logs: unit['logs']
      }
    end
  end

  # 计算设备状态（基于脚本状态）
  def calculate_device_status(scripts)
    return 'pending' unless scripts && scripts.any?

    statuses = scripts.map { |s| s.is_a?(Hash) ? (s['status'] || s[:status]) : nil }.compact

    return 'running' if statuses.include?('running')
    return 'failed' if statuses.include?('failed')
    return 'completed' if statuses.all? { |s| s == 'completed' }
    return 'pending'
  end

  # 计算设备进度
  def calculate_device_progress(scripts)
    return 0 unless scripts && scripts.any?

    total = scripts.size
    completed = scripts.count do |s|
      status = s.is_a?(Hash) ? (s['status'] || s[:status]) : nil
      status == 'completed'
    end

    (completed.to_f / total * 100).to_i
  end

  # 找到当前正在执行的脚本（只返回真正正在执行的，否则返回nil）
  def find_current_script(scripts)
    return nil unless scripts && scripts.any?

    # 只找正在运行的
    running = scripts.find do |s|
      status = s.is_a?(Hash) ? (s['status'] || s[:status]) : nil
      status == 'running'
    end
    running ? (running['name'] || running[:name]) : nil
  end

  # 获取任务信息（解析task_json）
  def task_info
    definition = task_definition || {}
    LogService.info("[LocalTask] task_info 被调用，definition: #{definition.inspect[0..1000]}")

    # 如果有task_json字段，返回其值；否则返回definition本身（如果是有效格式）
    result = definition['task_json'] || definition[:task_json]

    if result.nil? || result.empty?
      # 检查 definition 是否已经是直接包含 devices/scripts 的格式
      if definition.key?('devices') || definition.key?(:devices) ||
         definition.key?('devs') || definition.key?(:devs)
        result = definition
      else
        result = {}
      end
    end

    LogService.info("[LocalTask] task_info 返回: #{result.inspect[0..1000]}")
    result
  end

  # 转换为API响应格式（包含未选择字段）
  def to_api_hash
    latest_exec = latest_execution
    base_hash = {
      id: id,
      name: name,
      description: description,
      task_definition: task_definition,
      unselected_device_ids: unselected_device_ids_array,
      unselected_script_ids: unselected_script_ids_array
    }

    return base_hash.merge({
      status: 'pending',
      status_text: '待执行',
      progress: 0,
      device_count: device_count,
      latest_execution_id: nil,
      created_at: created_at&.iso8601,
      updated_at: updated_at&.iso8601,
      execution_units: []
    }) unless latest_exec

    # 总是从数据库/文件加载完整的 execution_units（包含 log_file_path）
    latest_exec.load_status_from_file
    full_units = latest_exec.get_execution_units

    # 优先从内存中读取任务状态（TaskExecutionManager）
    mem_task = TaskExecutionManager.instance.get_task(latest_exec.id)
    if mem_task
      # 内存中有最新状态
      status_text_map = {
        'pending' => '待执行',
        'running' => '执行中',
        'completed' => '已完成',
        'failed' => '失败',
        'cancelled' => '已取消'
      }
      status = mem_task[:status] || mem_task['status'] || latest_exec.status
      mem_units = mem_task[:execution_units] || mem_task['execution_units'] || {}

      # 用内存中的动态状态更新 full_units
      updated_units = full_units
      if mem_units.any?
        updated_units = merge_mem_state(full_units, mem_units)
      end

      base_hash.merge({
        status: status,
        status_text: status_text_map[status] || latest_exec.status_text,
        progress: mem_task[:progress] || mem_task['progress'] || latest_exec.progress,
        device_count: device_count_from_units(updated_units),
        latest_execution_id: latest_exec.id,
        created_at: created_at&.iso8601,
        updated_at: updated_at&.iso8601,
        started_at: mem_task[:started_at] || mem_task['started_at'],
        execution_units: convert_execution_units_to_array(updated_units)
      })
    else
      # 内存中没有，从数据库读取
      base_hash.merge({
        status: latest_exec.status || 'pending',
        status_text: latest_exec.status_text || '待执行',
        progress: latest_exec.progress || 0,
        device_count: device_count_from_units(full_units),
        latest_execution_id: latest_exec.id,
        created_at: created_at&.iso8601,
        updated_at: updated_at&.iso8601,
        started_at: latest_exec.started_at&.iso8601,
        execution_units: convert_execution_units_to_array(full_units)
      })
    end
  end
end
