#include "Sprite.h"
#include "EngineCore/Game.h"
#include "Text.h"
#include "EngineFrame/Render/RenderManager.h"

void Sprite::Init()
{
    this->Size = m_texture->getSize();
    RenderBase::Init();
}

void Sprite::SetTexture(RefPtr<Texture> texture)
{
    m_texture = texture;
    Init();
    CalcRenderInfoLogic(); // 第一次计算
}

Sprite::Sprite(std::string imgPath, int Index)
{
    this->imgPath = imgPath;
    this->Index = Index;
    m_texture = new Texture();
    m_texture->Init(imgPath, Index);
    Init();
    CalcRenderInfoLogic(); // 第一次计算
}

Sprite::Sprite(std::string PngPath)
{
    m_texture = new Texture();
    m_texture->Init(PngPath);
    Init();
    CalcRenderInfoLogic(); // 第一次计算
}

Sprite::~Sprite()
{
}

RefPtr<Texture> Sprite::GetTexture()
{
    return m_texture;
}

GlMatrix Sprite::matrix3x2ToGLMatrix(const Matrix3x2 &mat)
{
    return {
        // 列0：x轴线性变换
        mat._11, // [0][0]
        mat._12, // [1][0]
        0.0f,    // [2][0]
        0.0f,    // [3][0]

        // 列1：y轴线性变换
        mat._21, // [0][1]
        mat._22, // [1][1]
        0.0f,    // [2][1]
        0.0f,    // [3][1]

        // 列2：z轴（固定）
        0.0f, // [0][2]
        0.0f, // [1][2]
        1.0f, // [2][2]
        0.0f, // [3][2]

        // 列3：平移
        mat._31, // [0][3]（x平移）
        mat._32, // [1][3]（y平移）
        0.0f,    // [2][3]
        1.0f     // [3][3]
    };
}

void Sprite::CalcRenderInfoLogic()
{
    // 获取至在最终的父对象检查是否显示
    BaseNode *parentNode = this->GetParent();
    while (parentNode != nullptr)
    {
        if (parentNode->Visible == false)
        {
            _RenderGuidanceInfo.Visible = false;
            return;
        }
        parentNode = parentNode->GetParent();
    }
    _RenderGuidanceInfo.Visible = true;

    // 计算缩放因子和翻转状态
    float scaleX = transformIter.scale.x * transform.scale.x;
    float scaleY = transformIter.scale.y * transform.scale.y;

    // X轴和Y轴上是否翻转的标志
    bool flipX = scaleX < 0;
    bool flipY = scaleY < 0;

    _RenderGuidanceInfo.flip = SDL_FLIP_NONE;
    // 更新翻转状态
    if (flipX)
        _RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_HORIZONTAL | _RenderGuidanceInfo.flip);
    if (flipY)
        _RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_VERTICAL | _RenderGuidanceInfo.flip);

    // 纹理数据里带的偏移数据 有这个偏移才能保证动画播放时视觉中心点在一个点上
    auto T_Size = m_texture->getSize();
    auto T_Pos = m_texture->getPos();
    float texturePosX = flipX ? -(T_Size.width + T_Pos.x) + SDL_abs(transform.position.x * 2) : T_Pos.x;
    float texturePosY = flipY ? -(T_Size.height + T_Pos.y) + SDL_abs(transform.position.y * 2) : T_Pos.y;

    // 先计算Img坐标与精灵坐标合成后的真实坐标
    float RealPosX = transform.position.x + texturePosX;
    float RealPosY = transform.position.y + texturePosY;

    // 计算在世界中的位置
    float baseX = transformIter.position.x + RealPosX;
    float baseY = transformIter.position.y + RealPosY;

    // 获取当前帧的原始尺寸
    int frameWidth = Size.width;
    int frameHeight = Size.height;

    // 原始锚点偏移（基于帧尺寸）
    float origAnchorOffsetX = int(frameWidth * Anchor.x);
    float origAnchorOffsetY = int(frameHeight * Anchor.y);

    // 缩放的绝对值
    float absScaleX = SDL_fabs(scaleX);
    float absScaleY = SDL_fabs(scaleY);
    // 缩放后的尺寸
    float scaledWidth = frameWidth * absScaleX;
    float scaledHeight = frameHeight * absScaleY;
    // 缩放后的锚点偏移
    float scaledAnchorOffsetX = int(origAnchorOffsetX * absScaleX);
    float scaledAnchorOffsetY = int(origAnchorOffsetY * absScaleY);

    // 计算缩放后的锚点偏移与原锚点偏移的差值
    float scaleOffsetX = scaledAnchorOffsetX - origAnchorOffsetX;
    float scaleOffsetY = scaledAnchorOffsetY - origAnchorOffsetY;

    // 最终位置计算：世界位置 + 缩放锚点差值 - 缩放后的锚点偏移 + 纹理数据里带的偏移数据 (计算出绘制点的左上角)
    float Xpos = baseX - scaleOffsetX;
    float Ypos = baseY - scaleOffsetY;

    Xpos = (int)Xpos; // 强制转换为整数
    Ypos = (int)Ypos; // 强制转换为整数

    // 更新渲染信息
    _RenderGuidanceInfo.rect = {Xpos, Ypos, scaledWidth, scaledHeight};
    _RenderGuidanceInfo.AnchorPos = {scaledAnchorOffsetX, scaledAnchorOffsetY};
    // 设置纹理透明度
    m_texture->setAlpha(this->Alpha);

    // 屏幕内检测
    int screenWidth = Game::GetInstance().Screen_W;
    int screenHeight = Game::GetInstance().Screen_H;
    bool isInScreen = (Xpos + scaledWidth >= 0 && Xpos <= screenWidth && Ypos + scaledHeight >= 0 && Ypos <= screenHeight);
    _RenderGuidanceInfo.IsInScreen = isInScreen;

    // this->Size = {scaledWidth, scaledHeight};
    _RenderGuidanceInfo.rotation = transformIter.rotation + transform.rotation;

    CalcRenderInfoFlag = false;
}

void Sprite::PreRender()
{
    if (CalcRenderInfoFlag && Visible)
        CalcRenderInfoLogic();
}

void Sprite::Render()
{
    if (!Visible)
        return;
    if (!m_texture)
        return;

    RenderManager *renderer = Game::GetInstance().GetRenderer();

    if (_RenderGuidanceInfo.IsInScreen && _RenderGuidanceInfo.Visible)
    {
        SDL_FPoint AnchorPos;
        AnchorPos.x = _RenderGuidanceInfo.AnchorPos.x;
        AnchorPos.y = _RenderGuidanceInfo.AnchorPos.y;

        // 混合
        if (this->_BlendMode != NONE)
            Blend();

        SDL_Rect srcrect = {0, 0, this->Size.width, this->Size.height};
        renderer->DrawTexture(m_texture, &srcrect, &_RenderGuidanceInfo.rect, _RenderGuidanceInfo.rotation, &AnchorPos, _RenderGuidanceInfo.flip);

        // 还原混合
        if (this->_BlendMode != NONE)
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    }
}

void Sprite::Clear()
{
}



void Sprite::Blend()
{
    switch (this->_BlendMode)
    {
    case LINEARDODGE:
        glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
        break;
    }
}
