#include "SkData.h"
#include "SkImage.h"
#include "SkStream.h"
#include "SkSurface.h"
#include "rive/file.hpp"
#include "rive/math/aabb.hpp"
#include "skia_factory.hpp"
#include "skia_renderer.hpp"
#include <cstdio>
#include <stdio.h>
#include <string>
#include <iostream>
#include <sstream>

std::string getFileName(char* path)
{
    std::string str(path);

    const size_t from = str.find_last_of("\\/");
    const size_t to = str.find_last_of(".");
    return str.substr(from + 1, to - from - 1);
}

const int DEFAULT_SIZE = 256;

int getArg(char* arg)
{
    std::istringstream ss(arg);
    int x;
    if (!(ss >> x))
    {
        std::cerr << "Invalid number: " << arg << '\n';
    }
    else if (!ss.eof())
    {
        std::cerr << "Trailing chars after number: " << arg << '\n';
    }
    return x == 0 ? DEFAULT_SIZE : x;
}

int main(int argc, char* argv[])
{
    rive::SkiaFactory factory;

    if (argc < 2)
    {
        fprintf(stderr, "must pass source file");
        return 1;
    }
    FILE* fp = fopen(argv[1], "rb");

    const char* outPath;
    std::string filename;
    std::string fullName;
    if (argc > 2)
    {
        outPath = argv[2];
    }
    else
    {
        filename = getFileName(argv[1]);
        fullName = filename + ".png";
        outPath = fullName.c_str();
    }

    int width = DEFAULT_SIZE, height = DEFAULT_SIZE;
    if (argc == 5)
    {
        width = getArg(argv[3]);
        height = getArg(argv[4]);
    }

    if (fp == nullptr)
    {
        fprintf(stderr, "Failed to open rive file.\n");
        return 1;
    }
    fseek(fp, 0, SEEK_END);
    auto length = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    std::vector<uint8_t> bytes(length);
    if (fread(bytes.data(), 1, length, fp) != length)
    {
        fprintf(stderr, "Failed to read rive file.\n");
        fclose(fp);
        return 1;
    }
    fclose(fp);

    auto file = rive::File::import(bytes, &factory);
    if (!file)
    {
        fprintf(stderr, "Failed to read rive file.\n");
        return 1;
    }
    auto artboard = file->artboardDefault();
    artboard->advance(0.0f);

    sk_sp<SkSurface> rasterSurface =
        SkSurface::MakeRasterN32Premul(width, height);
    SkCanvas* rasterCanvas = rasterSurface->getCanvas();

    rive::SkiaRenderer renderer(rasterCanvas);
    renderer.save();
    renderer.align(rive::Fit::cover,
                   rive::Alignment::center,
                   rive::AABB(0, 0, width, height),
                   artboard->bounds());
    artboard->draw(&renderer);
    renderer.restore();

    sk_sp<SkImage> img(rasterSurface->makeImageSnapshot());
    if (!img)
    {
        return 1;
    }
    sk_sp<SkData> png(img->encodeToData());
    if (!png)
    {
        return 1;
    }
    SkFILEWStream out(outPath);
    (void)out.write(png->data(), png->size());
    return 0;
}
