(function () {
'use strict';

// JimSSng - 시체 색상 빛기둥 v1.0.0
// JimSSng - 아이템 드롭 오버레이의 corpseColorPillar 기능만 분리한 버전입니다.
// combined.timelines의 hth_dead만 스마트패치하고 기존 이벤트는 보존합니다.

function getModConfig() {
  var value = {};
  try {
    if (typeof config !== "undefined" && config) {
      value = config;
    } else if (D2RMM.getConfigJSON) {
      value = D2RMM.getConfigJSON();
    }
  } catch (e) {
    value = {};
  }

  if (typeof value === "string") {
    try {
      value = JSON.parse(value);
    } catch (e2) {
      value = {};
    }
  }
  return value || {};
}

function d2path(path) {
  return String(path || "").replace(/\//g, "\\");
}

function copyFile(src, dst, overwrite) {
  D2RMM.copyFile(d2path(src), d2path(dst), overwrite);
}

var modConfig = getModConfig();
var corpseColorPillarEnabled = modConfig.corpseColorPillarEnabled !== false;
var DEFAULT_CORPSE_COLOR_PILLAR = "gold2";

function parsePillarCode(rawValue) {
  var raw = String(rawValue == null ? "" : rawValue).replace(/\s+/g, "").toLowerCase();
  if (!raw || raw === "0") return null;

  var match = /^(red|orange|gold|peach|white|yellow|green|cyan|blue|navy|pink|magenta)([123])$/.exec(raw);
  if (!match) {
    console.log("[WARN] invalid corpse pillar code '" + raw + "'. Use color1~color3. Example: red1, red2, gold3.");
    return null;
  }
  return { color: match[1], pattern: match[2] };
}

function getCorpsePillarSetting() {
  var raw = modConfig.corpseColorPillar;
  if (raw == null) raw = DEFAULT_CORPSE_COLOR_PILLAR;
  return parsePillarCode(raw);
}

function pillarVariantName(setting) {
  return setting.color + setting.pattern;
}

var PLAYER_CORPSE_TIMELINE_CLASSES = [
  "amazon", "assassin", "barbarian", "druid",
  "necromancer", "paladin", "sorceress", "warlock"
];

// 원 통합 구현과 같은 prefix를 유지하여 두 모드가 함께 설치되어도 중복 적층되지 않게 합니다.
var CORPSE_COLOR_PILLAR_PREFIX = "jimssng_itemoverlay_corpse_color_pillar_";
var CORPSE_COLOR_PILLAR_OFFSETS_Y = [0.0, 2.7, 6.0, 10.0, 15.0, 20.0, 25.0];

function createCorpseShieldLayerEvent(duration) {
  return {
    type: "ChangeEquipmentLayerWeight",
    name: "ChangeEquipmentLayerWeight_Item034",
    eventTimestamp: 0.0,
    duration: duration,
    isCritical: false,
    eventParams: [
      { type: "ChangeEquipmentLayerWeightLayerNameEventParameter", name: "ChangeEquipmentLayerWeight_Track_eventParams_layerName069", value: "ShieldEquipLayer", parameterName: "layerName" },
      { type: "ChangeEquipmentLayerWeightWeightEventParameter", name: "ChangeEquipmentLayerWeight_Track_eventParams_weight069", value: 0.0, parameterName: "weight" },
      { type: "ChangeEquipmentLayerWeightBlendInTimeEventParameter", name: "ChangeEquipmentLayerWeight_Track_eventParams_blendInTime069", value: 0.25, parameterName: "blendInTime" },
      { type: "ChangeEquipmentLayerWeightBlendOutTimeEventParameter", name: "ChangeEquipmentLayerWeight_Track_eventParams_blendOutTime069", value: 0.25, parameterName: "blendOutTime" }
    ]
  };
}

function createCorpseColorPillarEvent(name, particlePath, yOffset) {
  return {
    type: "SpawnVFX",
    name: name,
    eventTimestamp: 0.0,
    duration: -1.0,
    isCritical: false,
    eventParams: [
      { type: "VFXSourceAnimationEventParameter", name: name + "_filename", value: particlePath, parameterName: "filename" },
      { type: "AttachToEntityAnimationEventParameter", name: name + "_attachToEntity", value: true, parameterName: "attachToEntity" },
      { type: "BoneNameAnimationEventParameter", name: name + "_boneName", value: "root", parameterName: "boneName" },
      { type: "OrientationBoneNameAnimationEventParameter", name: name + "_orientationBoneName", value: "root", parameterName: "orientationBoneName" },
      { type: "TranslationOffsetAnimationEventParameter", name: name + "_translationOffset", value: { x: 0.0, y: yOffset, z: 0.0 }, parameterName: "translationOffset" },
      { type: "RotationOffsetAnimationEventParameter", name: name + "_rotationOffset", value: { x: 0.0, y: 0.0, z: 0.0 }, parameterName: "rotationOffset" },
      { type: "HardKillVFXAnimationEventParameter", name: name + "_hardKill", value: false, parameterName: "hardKillOnTimeout" },
      { type: "AttachToDeadBodyEventParameter", name: name + "_attachToDeadBody", value: true, parameterName: "attachToDeadBody" }
    ]
  };
}

function removeOwnCorpseColorPillarEvents(events) {
  var next = [];
  for (var i = 0; i < events.length; i++) {
    var eventName = String(events[i] && events[i].name || "");
    if (eventName.indexOf(CORPSE_COLOR_PILLAR_PREFIX) !== 0) next.push(events[i]);
  }
  return next;
}

function looksLikeVanillaPaladinDeadTimeline(timeline) {
  if (!timeline || timeline.type !== "AnimationTimeline" || timeline.name !== "hth_dead") return false;
  if (Math.abs(Number(timeline.duration) - 0.3333333) > 0.000001) return false;
  if (Math.abs(Number(timeline.timeStep) - 0.03333334) > 0.000001) return false;
  if (!Array.isArray(timeline.animationEvents) || timeline.animationEvents.length !== 1) return false;
  return timeline.animationEvents[0] && timeline.animationEvents[0].type === "ChangeEquipmentLayerWeight";
}

function setTimelineImmediatelyAfter(timelines, afterKey, targetKey, targetValue) {
  var rebuilt = {};
  var inserted = false;
  var keys = Object.keys(timelines || {});
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    if (key === targetKey) continue;
    rebuilt[key] = timelines[key];
    if (key === afterKey) {
      rebuilt[targetKey] = targetValue;
      inserted = true;
    }
  }
  if (!inserted) rebuilt[targetKey] = targetValue;
  return rebuilt;
}

function copySelectedColorLightAssets(setting) {
  var variant = pillarVariantName(setting);
  var sourceBase = "assets/hd/vfx/colorlight/";
  var targetBase = "hd/vfx/colorlight/";

  // 선택된 색상에 실제 필요한 3개만 설치합니다.
  copyFile(sourceBase + "drop_light_" + variant + ".particles", targetBase + "drop_light_" + variant + ".particles", true);
  copyFile(sourceBase + "color_light.texture", targetBase + "color_light.texture", true);
  copyFile(sourceBase + variant + ".texture", targetBase + variant + ".texture", true);
}

function patchPlayerCorpseColorPillar(setting) {
  var particlePath = "data/hd/vfx/colorlight/drop_light_" + pillarVariantName(setting) + ".particles";

  for (var ci = 0; ci < PLAYER_CORPSE_TIMELINE_CLASSES.length; ci++) {
    var className = PLAYER_CORPSE_TIMELINE_CLASSES[ci];
    var filePath = "hd\\character\\player\\" + className + "\\animation\\combined.timelines";

    // 가능한 경우 존재 여부를 먼저 확인해 readJson file-not-found 경고를 피합니다.
    if (typeof D2RMM.isGameFile === "function") {
      try {
        if (!D2RMM.isGameFile(filePath)) continue;
      } catch (ignoredIsGameFileError) {}
    }

    var timelineData;
    try {
      timelineData = D2RMM.readJson(filePath);
    } catch (readError) {
      console.log("[WARN] corpse color pillar timeline skipped: " + filePath);
      continue;
    }

    if (!timelineData || typeof timelineData !== "object") continue;
    if (!timelineData.timelines || typeof timelineData.timelines !== "object") timelineData.timelines = {};

    var hthDead = timelineData.timelines.hth_dead;
    var changed = false;

    if (!hthDead) {
      hthDead = {
        type: "AnimationTimeline",
        name: "hth_dead",
        duration: 0.0,
        timeStep: 0.03333334,
        animationEvents: [createCorpseShieldLayerEvent(-1.0)]
      };
      timelineData.timelines = setTimelineImmediatelyAfter(timelineData.timelines, "hth_death", "hth_dead", hthDead);
      changed = true;
    } else {
      if (!Array.isArray(hthDead.animationEvents)) hthDead.animationEvents = [];
      if (className === "paladin" && looksLikeVanillaPaladinDeadTimeline(hthDead)) {
        hthDead.duration = 0.0;
        changed = true;
      }
    }

    var oldLength = hthDead.animationEvents.length;
    hthDead.animationEvents = removeOwnCorpseColorPillarEvents(hthDead.animationEvents);
    if (hthDead.animationEvents.length !== oldLength) changed = true;

    for (var bi = 0; bi < CORPSE_COLOR_PILLAR_OFFSETS_Y.length; bi++) {
      hthDead.animationEvents.push(createCorpseColorPillarEvent(
        CORPSE_COLOR_PILLAR_PREFIX + bi,
        particlePath,
        CORPSE_COLOR_PILLAR_OFFSETS_Y[bi]
      ));
      changed = true;
    }

    if (changed) D2RMM.writeJson(filePath, timelineData);
  }
}

if (!corpseColorPillarEnabled) return;

var setting = getCorpsePillarSetting();
if (!setting) return;

copySelectedColorLightAssets(setting);
patchPlayerCorpseColorPillar(setting);

})();
