#include <frostbite2D/animation/animation_data.h>
#include <frostbite2D/resource/binary_reader.h>
#include <frostbite2D/resource/pvf_archive.h>
#include <algorithm>
#include <cctype>
#include <sstream>

namespace frostbite2D {

namespace animation {

// ---------------------------------------------------------------------------
// 工具函数实现
// ---------------------------------------------------------------------------

static std::string toLowerCase(const std::string& str) {
  std::string result = str;
  std::transform(result.begin(), result.end(), result.begin(),
                 [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
  return result;
}

std::string getAniFlag(int type) {
  switch (type) {
    case 0:   return {"LOOP"};
    case 1:   return {"SHADOW"};
    case 3:   return {"COORD"};
    case 7:   return {"IMAGE_RATE"};
    case 8:   return {"IMAGE_ROTATE"};
    case 9:   return {"RGBA"};
    case 10:  return {"INTERPOLATION"};
    case 11:  return {"GRAPHIC_EFFECT"};
    case 12:  return {"DELAY"};
    case 13:  return {"DAMAGE_TYPE"};
    case 14:  return {"DAMAGE_BOX"};
    case 15:  return {"ATTACK_BOX"};
    case 16:  return {"PLAY_SOUND"};
    case 17:  return {"PRELOAD"};
    case 18:  return {"SPECTRUM"};
    case 23:  return {"SET_FLAG"};
    case 24:  return {"FLIP_TYPE"};
    case 25:  return {"LOOP_START"};
    case 26:  return {"LOOP_END"};
    case 27:  return {"CLIP"};
    case 28:  return {"OPERATION"};
    default:  return {};
  }
}

std::string getAniEffectType(int type) {
  switch (type) {
    case 0: return {"NONE"};
    case 1: return {"DODGE"};
    case 2: return {"LINEARDODGE"};
    case 3: return {"DARK"};
    case 4: return {"XOR"};
    case 5: return {"MONOCHROME"};
    case 6: return {"SPACEDISTORT"};
    default: return {};
  }
}

std::string getAniFlipType(int type) {
  switch (type) {
    case 1: return {"HORIZON"};
    case 2: return {"VERTICAL"};
    case 3: return {"ALL"};
    default: return {};
  }
}

std::string getAniDamageType(int type) {
  switch (type) {
    case 0: return {"NORMAL"};
    case 1: return {"SUPERARMOR"};
    case 2: return {"UNBREAKABLE"};
    default: return {};
  }
}

// ---------------------------------------------------------------------------
// 辅助函数
// ---------------------------------------------------------------------------

static uint8 read256(BinaryReader& reader) {
  uint8 value = reader.readUInt8();
  return value == 255 ? 256 : value;
}

static uint16 readUShort(BinaryReader& reader) {
  return reader.readUInt16();
}

static int16 readShort(BinaryReader& reader) {
  return reader.readInt16();
}

// ---------------------------------------------------------------------------
// 解析函数实现
// ---------------------------------------------------------------------------

AniInfo parseAniInfo(const char* data, size_t size) {
  AniInfo info;
  BinaryReader reader(data, size);

  if (!reader.isOpen() || reader.size() < 4) {
    return info;
  }

  uint16 frameMax = reader.readUInt16();
  uint16 imgCount = reader.readUInt16();

  for (uint16 i = 0; i < imgCount; i++) {
    int buf = reader.readInt32();
    std::string imgPath = "sprite/" + reader.readString(buf);
    info.imgList.push_back(toLowerCase(imgPath));
  }

  uint16 aniHeaderItemCount = reader.readUInt16();
  for (uint16 i = 0; i < aniHeaderItemCount; i++) {
    uint16 type = reader.readUInt16();
    switch (type) {
      case 0:
      case 1: {
        std::string key = getAniFlag(type);
        int value = reader.readUInt8();
        if (!key.empty()) {
          info.flag.emplace(key, value);
        }
        break;
      }
      case 3:
      case 28: {
        std::string key = getAniFlag(type);
        int value = reader.readUInt16();
        if (!key.empty()) {
          info.flag.emplace(key, value);
        }
        break;
      }
      case 18: {
        reader.readUInt8();
        reader.readInt32();
        reader.readInt32();
        reader.readInt32();
        read256(reader);
        read256(reader);
        read256(reader);
        read256(reader);
        reader.readUInt16();
        break;
      }
      default:
        break;
    }
  }

  for (uint16 i = 0; i < frameMax; i++) {
    AniFrame frame;

    uint16 boxItemCount = reader.readUInt16();
    for (uint16 j = 0; j < boxItemCount; j++) {
      uint16 boxType = reader.readUInt16();
      std::vector<int> boxData;
      for (int k = 0; k < 6; k++) {
        boxData.push_back(reader.readInt32());
      }
      if (boxType == 15) {
        frame.attackBox.push_back(boxData);
      } else {
        frame.damageBox.push_back(boxData);
      }
    }

    int16 indexBuf = reader.readInt16();
    if (indexBuf != -1) {
      frame.imgPath = info.imgList[indexBuf];
      frame.imgIndex = reader.readUInt16();
    } else {
      frame.imgPath = "";
      frame.imgIndex = 0;
    }

    frame.imgPos.x = static_cast<float>(reader.readInt32());
    frame.imgPos.y = static_cast<float>(reader.readInt32());

    uint16 imgFlagCount = reader.readUInt16();
    for (uint16 j = 0; j < imgFlagCount; j++) {
      uint16 imgFlagType = reader.readUInt16();
      std::string key;
      int value;

      switch (imgFlagType) {
        case 0:
        case 1:
        case 10: {
          key = getAniFlag(imgFlagType);
          value = reader.readUInt8();
          if (!key.empty()) {
            frame.flag.emplace(key, value);
          }
          break;
        }
        case 3: {
          key = "COORD";
          value = reader.readUInt16();
          frame.flag.emplace(key, value);
          break;
        }
        case 17: {
          key = "PRELOAD";
          value = 1;
          frame.flag.emplace(key, value);
          break;
        }
        case 7: {
          key = "IMAGE_RATE";
          Vec2 rate{reader.readFloat(), reader.readFloat()};
          frame.flag.emplace(key, rate);
          break;
        }
        case 8: {
          key = "IMAGE_ROTATE";
          float rateBuffer = reader.readFloat();
          frame.flag.emplace(key, rateBuffer);
          break;
        }
        case 9: {
          key = "RGBA";
          std::vector<int> rgba = {
              static_cast<int>(read256(reader)),
              static_cast<int>(read256(reader)),
              static_cast<int>(read256(reader)),
              static_cast<int>(read256(reader))};
          frame.flag.emplace(key, rgba);
          break;
        }
        case 11: {
          uint16 effectType = reader.readUInt16();
          key = "GRAPHIC_EFFECT_" + getAniEffectType(effectType);
          std::vector<float> effect;
          switch (effectType) {
            case 5:
              effect.push_back(static_cast<float>(read256(reader)));
              effect.push_back(static_cast<float>(read256(reader)));
              effect.push_back(static_cast<float>(read256(reader)));
              break;
            case 6:
              effect.push_back(static_cast<float>(read256(reader)));
              effect.push_back(static_cast<float>(read256(reader)));
              break;
          }
          frame.flag.emplace(key, effect);
          break;
        }
        case 12: {
          value = reader.readInt32();
          frame.delay = value;
          break;
        }
        case 13: {
          key = "DAMAGE_TYPE";
          std::string dtype = getAniDamageType(reader.readUInt16());
          frame.flag.emplace(key, dtype);
          break;
        }
        case 16: {
          int soundSize = reader.readInt32();
          key = "PLAY_SOUND";
          std::string sound = reader.readString(soundSize);
          frame.flag.emplace(key, sound);
          break;
        }
        case 23: {
          key = "SET_FLAG";
          value = reader.readInt32();
          frame.flag.emplace(key, value);
          break;
        }
        case 24: {
          key = "FLIP_TYPE";
          std::string ftValue = getAniFlipType(reader.readUInt16());
          frame.flag.emplace(key, ftValue);
          break;
        }
        case 25: {
          key = "LOOP_START";
          frame.flag.emplace(key, 1);
          break;
        }
        case 26: {
          key = "LOOP_END";
          value = reader.readInt32();
          frame.flag.emplace(key, value);
          break;
        }
        case 27: {
          key = "CLIP";
          std::vector<int> clipArr = {
              reader.readInt16(),
              reader.readInt16(),
              reader.readInt16(),
              reader.readInt16()};
          frame.flag.emplace(key, clipArr);
          break;
        }
        default:
          break;
      }
    }

    info.frames.push_back(frame);
  }

  return info;
}

std::optional<AniInfo> parseAniFromPvf(const std::string& path) {
  auto& pvf = PvfArchive::get();
  if (!pvf.isOpen()) {
    return std::nullopt;
  }

  auto rawData = pvf.getFileRawData(path);
  if (!rawData) {
    return std::nullopt;
  }

  return parseAniInfo(rawData->data.get(), rawData->size);
}

AlsInfo parseAlsInfo(const std::string& data) {
  AlsInfo info;

  std::istringstream stream(data);
  std::string line;

  while (std::getline(stream, line)) {
    if (line.empty()) continue;

    std::istringstream lineStream(line);
    std::string segment;
    lineStream >> segment;

    if (segment == "[use animation]") {
      std::string aniPath, aniKey;
      lineStream >> aniPath >> aniKey;
      info.aniList[aniKey].path = toLowerCase(aniPath);
    } else if (segment == "[none effect add]") {
      int layer1, layer2;
      std::string aniKey;
      lineStream >> layer1 >> layer2 >> aniKey;
      info.aniList[aniKey].layer = {layer1, layer2};
    } else if (segment == "[add]") {
      int layer1, layer2;
      std::string aniKey;
      lineStream >> layer1 >> layer2 >> aniKey;
      info.aniList[aniKey].layer = {layer1, layer2};
    }
  }

  return info;
}

std::optional<AlsInfo> parseAlsFromPvf(const std::string& path) {
  auto& pvf = PvfArchive::get();
  if (!pvf.isOpen()) {
    return std::nullopt;
  }

  auto content = pvf.getFileContent(path);
  if (!content) {
    return std::nullopt;
  }

  return parseAlsInfo(*content);
}

} // namespace animation

} // namespace frostbite2D
