#include "GameMap.h"
#include "Asset/AssetManager.h"
#include "EngineFrame/Scene/Scene.h"
#include "EngineFrame/Component/Animation.h"
#include "Actor/Map/GameMapCamera.h"
#include "Actor/Object/CharacterObject.h"
#include "EngineCore/Game.h"

GameMap::GameMap()
{
    _LayerMap["contact"] = new GameMapLayer();
    _LayerMap["distantback"] = new GameMapLayer();
    _LayerMap["middleback"] = new GameMapLayer();
    _LayerMap["bottom"] = new GameMapLayer();
    _LayerMap["closeback"] = new GameMapLayer();
    _LayerMap["normal"] = new GameMapLayer();
    _LayerMap["close"] = new GameMapLayer();
    _LayerMap["cover"] = new GameMapLayer();
    _LayerMap["max"] = new GameMapLayer();

    // 设置图层渲染顺序
    _LayerMap["contact"]->SetRenderZOrder(10000);
    _LayerMap["distantback"]->SetRenderZOrder(50000);
    _LayerMap["middleback"]->SetRenderZOrder(100000);
    _LayerMap["bottom"]->SetRenderZOrder(150000);
    _LayerMap["closeback"]->SetRenderZOrder(200000);
    _LayerMap["normal"]->SetRenderZOrder(250000);
    _LayerMap["close"]->SetRenderZOrder(300000);
    _LayerMap["cover"]->SetRenderZOrder(350000);
    _LayerMap["max"]->SetRenderZOrder(400000);
}

GameMap::~GameMap()
{
}

void GameMap::InitConfiguration(std::string mapName)
{
    ScriptData Data = AssetManager::GetInstance().GetScriptInfo(mapName);
    _MapInfo["wide_mode_camer_vertical_correction"] = 0;
    _MapInfo["background_pos"] = 0;
    _MapPath = mapName;
    _MapDir = mapName.substr(0, mapName.find_last_of("/") + 1);
    while (!Data.IsEnd())
    {
        std::string Segment = Data.Get();
        if (Segment == "[background pos]")
        {
            int Offset = std::stoi(Data.Get());
            MapOffsetY = Offset;
            _MapInfo["background_pos"] = Offset;
        }
        else if (Segment == "[map name]")
        {
            _MapInfo["name"] = Data.Get();
        }
        else if (Segment == "[limit map camera move]")
        {
            std::vector<int> limit;
            limit.push_back(std::stoi(Data.Get()));
            limit.push_back(std::stoi(Data.Get()));
            limit.push_back(std::stoi(Data.Get()));
            limit.push_back(std::stoi(Data.Get()));
            _MapInfo["limit_map_camera_move"] = limit;
        }
        else if (Segment == "[wide mode camera vertical correction]")
        {
            _MapInfo["wide_mode_camer_vertical_correction"] = std::stoi(Data.Get());
        }
        else if (Segment == "[tile]")
        {
            std::vector<std::string> tileArry;
            while (true)
            {
                auto tiledata = Data.Get();
                if (tiledata == "[/tile]")
                    break;
                tileArry.push_back(_MapDir + Tool_toLowerCase(tiledata));
            }
            _MapInfo["tile"] = tileArry;
        }
        else if (Segment == "[extended tile]")
        {
            std::vector<std::string> tileArry;
            while (true)
            {
                auto tiledata = Data.Get();
                if (tiledata == "[/extended tile]")
                    break;
                tileArry.push_back(_MapDir + Tool_toLowerCase(tiledata));
            }
            _MapInfo["extended_tile"] = tileArry;
        }
        else if (Segment == "[far sight scroll]" || Segment == "[middle sight scroll]" || Segment == "[near sight scroll]")
        {
            _MapInfo[Segment.substr(1, Segment.length() - 2)] = std::stoi(Data.Get());
        }
        else if (Segment == "[background animation]")
        {
            std::vector<BackGroundAni> Arr;
            while (true)
            {
                std::string aniData = Data.Get();
                if (aniData == "[/background animation]")
                    break;
                if (aniData == "[ani info]")
                {
                    BackGroundAni ani;
                    Data.Get();
                    ani.filename = _MapDir + Tool_toLowerCase(Data.Get());
                    Data.Get();
                    ani.layer = Data.Get();
                    Data.Get();
                    ani.order = Data.Get();
                    Arr.push_back(ani);
                }
            }
            _MapInfo["background_animation"] = Arr;
        }
        else if (Segment == "[sound]")
        {
            std::vector<std::string> soundArry;
            while (true)
            {
                std::string sounddata = Data.Get();
                if (sounddata == "[/sound]")
                    break;
                soundArry.push_back(sounddata);
            }
            _MapInfo["sound"] = soundArry;
        }
        else if (Segment == "[animation]")
        {
            std::vector<MapAni> aniArry;
            while (true)
            {
                std::string aniData = Data.Get();
                if (aniData == "[/animation]")
                    break;
                MapAni info;
                info.filename = Tool_RegRealPath(_MapDir + Tool_toLowerCase(aniData));
                info.layer = Data.Get();
                info.XPos = std::stoi(Data.Get());
                info.YPos = std::stoi(Data.Get());
                info.ZPos = std::stoi(Data.Get());
                aniArry.push_back(info);
            }
            _MapInfo["animation"] = aniArry;
        }
        else if (Segment == "[NPC]")
        {
            std::vector<MapNpc> npcArry;
            while (true)
            {
                std::string npcData = Data.Get();
                if (npcData == "[/NPC]")
                    break;
                MapNpc info;
                info.id = std::stoi(npcData);
                info.direction = Data.Get();
                info.XPos = std::stoi(Data.Get());
                info.YPos = std::stoi(Data.Get());
                info.ZPos = std::stoi(Data.Get());
                npcArry.push_back(info);
            }
            _MapInfo["NPC"] = npcArry;
        }
        else if (Segment == "[town movable area]")
        {
            std::vector<int> town_movable_area;
            std::vector<MapMoveArea> town_movable_area_info;
            while (true)
            {
                std::string areadata = Data.Get();
                if (areadata == "[/town movable area]")
                    break;
                town_movable_area.push_back(std::stoi(areadata));
                town_movable_area.push_back(std::stoi(areadata));
                town_movable_area.push_back(std::stoi(areadata));
                town_movable_area.push_back(std::stoi(areadata));
                MapMoveArea T;
                T.town = std::stoi(areadata);
                T.area = std::stoi(areadata);
                town_movable_area_info.push_back(T);
            }
            _MapInfo["town_movable_area"] = town_movable_area;
            _MapInfo["town_movable_area_info"] = town_movable_area_info;
        }
        else if (Segment == "[virtual movable area]")
        {
            std::vector<int> virtual_movable_area;
            while (true)
            {
                std::string areadata = Data.Get();
                if (areadata == "[/virtual movable area]")
                    break;
                virtual_movable_area.push_back(std::stoi(areadata));
                virtual_movable_area.push_back(std::stoi(Data.Get()));
                virtual_movable_area.push_back(std::stoi(Data.Get()));
                virtual_movable_area.push_back(std::stoi(Data.Get()));
            }
            _MapInfo["virtual_movable_area"] = virtual_movable_area;
        }
    }
}

void GameMap::InitTile()
{
    if (!_MapInfo.count("tile"))
        return;
    // 普通地板数量
    int NormalTileCount = 0;
    // 普通地板高度
    int NormalTileHeight = 560;
    std::vector<std::string> tileArr = std::get<std::vector<std::string>>(_MapInfo["tile"]);
    if (tileArr.size() > 0)
    {
        NormalTileCount = tileArr.size();
        _MapLength = NormalTileCount * 224;
        for (int i = 0; i < NormalTileCount; i++)
        {
            std::string path = tileArr[i];
            RefPtr<Tile> tile = new Tile(path);
            tile->SetPos(Vec2{i * 224, -200 - std::get<int>(_MapInfo["background_pos"])});
            _LayerMap["bottom"]->AddComponent(tile);
        }
        _MapHeight = 560;
    }
    if (_MapInfo.count("extended_tile"))
    {
        std::vector<std::string> extileArr = std::get<std::vector<std::string>>(_MapInfo["extended_tile"]);
        if (extileArr.size() > 0)
        {
            int ExTileCount = extileArr.size();
            int Buffer = (ExTileCount / NormalTileCount);
            _MapHeight += (Buffer < 1 ? 1 : Buffer) * 40;
            for (int i = 0; i < ExTileCount; i++)
            {
                std::string path = extileArr[i];
                RefPtr<Tile> tile = new Tile(path);
                int xbuf = i % NormalTileCount * 224;
                int ybuf = -200 - std::get<int>(_MapInfo["background_pos"]) + NormalTileHeight + 120 * (i / NormalTileCount);
                tile->SetPos(Vec2{xbuf, ybuf});
                _LayerMap["bottom"]->AddComponent(tile);
            }
        }
    }
}

void GameMap::InitBackgroundAnimation()
{
    float Rate = _MapInfo.count("far_sight_scroll") ? std::get<int>(_MapInfo["far_sight_scroll"]) / 100.0f : 1.0f;
    (void)Rate;
    // TODO 摄像机
    if (_MapInfo.count("background_animation"))
    {
        std::vector<BackGroundAni> aniArr = std::get<std::vector<BackGroundAni>>(_MapInfo["background_animation"]);
        for (auto &ani : aniArr)
        {
            std::string path = ani.filename;
            std::vector<RefPtr<Animation>> AniList;
            RefPtr<Animation> AniObj = new Animation(path);
            int width = AniObj->GetSize().width;
            AniList.push_back(AniObj);
            for (int i = 0; i < (_MapLength * Rate) / width; i++)
            {
                RefPtr<Animation> AniObj = new Animation(path);
                AniList.push_back(AniObj);
            }
            for (int i = 0; i < (int)AniList.size(); i++)
            {
                AniList[i]->SetPos(Vec2{i * width, -120});
                AniList[i]->SetRenderZOrder(-1000000);
                std::string layer = ani.layer;
                layer = layer.substr(1, layer.length() - 2);
                if (_LayerMap.count(layer))
                {
                    _LayerMap[layer]->AddChild(AniList[i]);
                }
                else
                {
                }
            }
        }
    }
}

void GameMap::InitMapAnimation()
{
    if (_MapInfo.count("animation"))
    {
        std::vector<MapAni> aniArr = std::get<std::vector<MapAni>>(_MapInfo["animation"]);
        for (auto &ani : aniArr)
        {
            std::string path = ani.filename;
            RefPtr<Animation> AniObj = new Animation(path);
            AniObj->SetPos(Vec2{ani.XPos, ani.YPos - ani.ZPos});
            AniObj->SetRenderZOrder(ani.YPos);
            std::string layer = ani.layer;
            layer = layer.substr(1, layer.length() - 2);
            if (_LayerMap.count(layer))
            {
                _LayerMap[layer]->AddChild(AniObj);
            }
        }
    }
}

void GameMap::InitVirtualMovableArea()
{
    std::vector<int> Info = std::get<std::vector<int>>(_MapInfo["virtual_movable_area"]);
    if (Info.size() > 0)
    {
        for (int i = 0; i < Info.size(); i += 4)
        {
            float x = Info[i];
            float y = Info[i + 1];
            float w = Info[i + 2];
            float h = Info[i + 3];
            if (_DebugMode)
                _LayerMap["max"]->AddDebugFeasibleAreaInfo(Vec2(x, y), VecSize(w, h));
            _MovableArea.push_back(SDL_FRect{x, y, w, h});
        }
    }
}

void GameMap::LoadMap(std::string mapName)
{
    // 读取脚本配置
    InitConfiguration(mapName);
    // 初始化地板
    InitTile();
    // 初始化背景动画
    InitBackgroundAnimation();
    // 初始化场景Ani
    InitMapAnimation();
    // 初始化可行区域
    InitVirtualMovableArea();
}

void GameMap::Enter(Scene *scene)
{
    _Scene = scene;
    scene->AddChild(_LayerMap["contact"]);
    scene->AddChild(_LayerMap["distantback"]);
    scene->AddChild(_LayerMap["middleback"]);
    scene->AddChild(_LayerMap["bottom"]);
    scene->AddChild(_LayerMap["closeback"]);
    scene->AddChild(_LayerMap["normal"]);
    scene->AddChild(_LayerMap["close"]);
    scene->AddChild(_LayerMap["cover"]);
    scene->AddChild(_LayerMap["max"]);
}

void GameMap::HandleEvents(SDL_Event *e)
{
}

void GameMap::Update(float deltaTime)
{
    if (_Scene->GetCamera() == nullptr)
        return;
    GameMapCamera *Cam = (GameMapCamera *)(_Scene->GetCamera().Get());
    int targetX = Cam->_currentPosition.x;
    int targetY = Cam->_currentPosition.y;
    // 屏幕中心
    int width_Separate = 1067 / 2;
    int height_Separate = 600 / 2;

    // 获取摄像机可行区域限制
    auto limitIt = _MapInfo.find("limit_map_camera_move");
    if (limitIt != _MapInfo.end())
    {
        std::vector<int> limit = std::get<std::vector<int>>(_MapInfo["limit_map_camera_move"]);
        int X_Limit_Min = limit[0];
        int X_Limit_Max = limit[1];
        int Y_Limit_Min = limit[2];
        int Y_Limit_Max = limit[3];
        // 应用地图边界限制
        targetX = std::clamp(targetX, width_Separate, _MapLength - width_Separate);
        targetY = std::clamp(targetY, height_Separate, _MapHeight - height_Separate);
        // 应用自定义摄像机移动限制
        if (X_Limit_Min != -1)
            targetX = std::max(targetX, X_Limit_Min);
        if (X_Limit_Max != -1)
            targetX = std::min(targetX, X_Limit_Max);
        if (Y_Limit_Min != -1)
            targetY = std::max(targetY, Y_Limit_Min);
        if (Y_Limit_Max != -1)
            targetY = std::min(targetY, Y_Limit_Max);
    }

    // 更新图层位置
    for (auto &Layer : _LayerMap)
    {
        int posX = -targetX + width_Separate;
        int posY = -targetY + height_Separate + MapOffsetY;
        if (Layer.first == "distantback")
        {
            posX *= BackgroundMoveSpeed;
            posX /= 100;
        }
        Layer.second->SetPos(Vec2(posX, posY));
    }
}

void GameMap::AddObject(RefPtr<BaseObject> object)
{
    object->_AffMap = this;
    _LayerMap["normal"]->AddObject(object);
    // 如果是角色对象
    if (object->m_objecttype == ObjectType::CHARACTER)
    {
        CharacterObject *chr = (CharacterObject *)(object.Get());
        if( chr->_Shadow != nullptr)_LayerMap["bottom"]->AddComponent(chr->_Shadow);
    }
}

VecPos3 GameMap::CheckIsItMovable(VecPos3 CurPos, VecPos3 PosOffset)
{
    // 初始化结果为原坐标（默认不移动）
    VecPos3 result = CurPos;

    // 如果没有可移动区域限制，直接全量位移
    if (_MovableArea.empty())
    {
        result.x += PosOffset.x;
        result.y += PosOffset.y;
        result.z += PosOffset.z; // Z轴不受限
        return result;
    }

    // 计算X轴单独位移后的目标位置
    float targetX = CurPos.x + PosOffset.x;
    // 计算Y轴单独位移后的目标位置
    float targetY = CurPos.y + PosOffset.y;

    // 检查X轴位移是否合法（固定Y为当前值，仅移动X）
    SDL_FPoint xTestPoint{targetX, CurPos.y};
    bool isXValid = false;
    for (auto &area : _MovableArea)
    {
        if (SDL_PointInFRect(&xTestPoint, &area))
        {
            isXValid = true;
            break;
        }
    }

    // 检查Y轴位移是否合法（固定X为当前值，仅移动Y）
    SDL_FPoint yTestPoint{CurPos.x, targetY};
    bool isYValid = false;
    for (auto &area : _MovableArea)
    {
        if (SDL_PointInFRect(&yTestPoint, &area))
        {
            isYValid = true;
            break;
        }
    }

    // 应用合法的位移
    if (isXValid)
    {
        result.x = targetX; // X轴允许移动
    }
    if (isYValid)
    {
        result.y = targetY; // Y轴允许移动
    }
    // Z轴不受限制，直接应用位移
    result.z += PosOffset.z;

    return result;
}