#pragma once

#include "PdfObject.h"
#include "PdfStream.h"
#include "PdfXRefTable.h"

class PdfPageTree;

class PdfProcSet : public PdfObject
{
public:
    std::string ToString(PdfXRefTable* xRefTable) override
    {
        UpdateDictionary();
        auto content = GetStringPrefix();
        content += mDictionary.ToString();
        content += "[/PDF]\n";
        content += GetStringSuffix();
        xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);

        return content;
    }
};

class PdfFont : public PdfObject
{
public:
    std::string ToString(PdfXRefTable* xRefTable) override
    {
        UpdateDictionary();
        auto content = GetStringPrefix();
        content += mDictionary.ToString();
        content += GetStringSuffix();
        xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);
        return content;
    }

    void UpdateDictionary()
    {
        mDictionary.AddStringItem("Type", "/Font");
        mDictionary.AddStringItem("Subtype", "/Type1");
        mDictionary.AddStringItem("Name", "/F1");
        mDictionary.AddStringItem("BaseFont", "/Helvetica");
        mDictionary.AddStringItem("Encoding", "/MacRomanEncoding");
    }
};

class PdfPage : public PdfObject
{
public:
    PdfPage(PdfPageTree* parent)
        : mParent(parent)
    {
        mContent = std::make_unique<PdfStream>();

        std::string pageContent = "BT\n";
        pageContent += "/F1 24 Tf\n";
        pageContent += "100 100 Td\n";
        pageContent += "(Hello World) Tj\n";
        pageContent += "ET";

        mContent->SetContent(pageContent);
        mProcSet = std::make_unique<PdfProcSet>();

        mDefaultFont = std::make_unique<PdfFont>();
    }

    unsigned IndexObjects(unsigned count)
    {
        auto newCount = count + 1;
        mObjectNumber = newCount;
        newCount = mContent->IndexObjects(newCount);
        newCount = mProcSet->IndexObjects(newCount);
        newCount = mDefaultFont->IndexObjects(newCount);
        return newCount;
    }

    std::string ToString(PdfXRefTable* xRefTable) override
    {
        UpdateDictionary();
        auto content = GetStringPrefix();
        content += mDictionary.ToString();
        content += GetStringSuffix();
        xRefTable->AddRecord(content.size(), mGenerationNumber, mIsFree);

        content += mContent->ToString(xRefTable);

        content += mProcSet->ToString(xRefTable);

        content += mDefaultFont->ToString(xRefTable);

        return content;
    }

    void UpdateDictionary()
    {
        std::string mediaBox = "[0 0 " + std::to_string(mWidth) + " " + std::to_string(mHeight) + "]";
        mDictionary.AddStringItem("Type", "/Page");
        mDictionary.AddStringItem("MediaBox", mediaBox);
        mDictionary.AddStringItem("Parent", mParent->GetRefString());
        mDictionary.AddStringItem("Contents", mContent->GetRefString());

        auto resourcesDict = std::make_unique<PdfDictionary>();
        resourcesDict->AddStringItem("ProcSet", mProcSet->GetRefString());

        auto fontDict = std::make_unique<PdfDictionary>();
        fontDict->AddStringItem("F1", mDefaultFont->GetRefString());
        resourcesDict->AddDictItem("Font", std::move(fontDict));

        mDictionary.AddDictItem("Resources", std::move(resourcesDict));
    }

private:
    unsigned mWidth{612};
    unsigned mHeight{792};
    std::unique_ptr<PdfStream> mContent;
    std::unique_ptr<PdfFont> mDefaultFont;
    PdfObjectPtr mProcSet;
    PdfPageTree* mParent;

};
