#include <grp.h>
#include <luna/String.h>
#include <os/ArgumentParser.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

Result<int> luna_main(int argc, char** argv)
{
    StringView user_and_group;
    StringView path;

    os::ArgumentParser parser;
    parser.add_description("Change the owner and group of a file."_sv);
    parser.add_system_program_info("chown"_sv);
    parser.add_positional_argument(user_and_group, "owner"_sv, true);
    parser.add_positional_argument(path, "path"_sv, true);
    parser.parse(argc, argv);

    u32 uid = -1;
    Option<u32> gid = -1;

    auto names = TRY(user_and_group.split_once(':'));
    if (names.size() > 1)
    {
        auto& group = names[1];
        if (group.is_empty()) { gid = {}; }
        else
        {
            auto rc = group.view().to_uint();
            if (rc.has_value()) { gid = (u32)rc.value(); }
            else
            {
                struct group* grp = getgrnam(group.chars());
                if (!grp)
                {
                    fprintf(stderr, "%s: unknown group %s!\n", argv[0], group.chars());
                    return 1;
                }

                gid = grp->gr_gid;

                endgrent();
            }
        }
    }
    if (names.size() > 0)
    {
        auto& owner = names[0];
        if (!owner.is_empty())
        {
            auto rc = owner.view().to_uint();
            if (rc.has_value()) { uid = (u32)rc.value(); }
            else
            {
                struct passwd* pw = getpwnam(owner.chars());
                if (!pw)
                {
                    fprintf(stderr, "%s: unknown user %s!\n", argv[0], owner.chars());
                    return 1;
                }

                uid = pw->pw_uid;
            }

            if (!gid.has_value())
            {
                struct passwd* pw = getpwuid(uid);
                if (!pw)
                {
                    fprintf(stderr, "%s: unknown user id %u!\n", argv[0], uid);
                    return 1;
                }

                gid = pw->pw_gid;
            }

            endpwent();
        }
    }

    if (chown(path.chars(), uid, gid.value_or(-1)) < 0)
    {
        perror("chown");
        return 1;
    }

    return 0;
}