#include "AutoStart-MacOS.h"
#include "LogManager.h"
#include "filesystem.h"

#include <fstream>
#include <sstream>
#include <iostream>
#include <unistd.h>

#include <mach-o/dyld.h>

/*-----------------------------------------------------*\
| MacOS AutoStart Implementation                        |
| Public Methods                                        |
\*-----------------------------------------------------*/

AutoStart::AutoStart(std::string name)
{
    InitAutoStart(name);
}

bool AutoStart::DisableAutoStart()
{
    std::error_code autostart_file_remove_errcode;
    bool            success                         = false;

    /*-------------------------------------------------*\
    | Check if the filename is valid                    |
    \*-------------------------------------------------*/
    if(autostart_file != "")
    {
        /*---------------------------------------------*\
        | If file doesn't exist, disable is successful  |
        \*---------------------------------------------*/
        if(!filesystem::exists(autostart_file))
        {
            success = true;
        }
        /*---------------------------------------------*\
        | Otherwise, delete the file                    |
        \*---------------------------------------------*/
        else
        {
            success = filesystem::remove(autostart_file, autostart_file_remove_errcode);

            if(!success)
            {
                LOG_ERROR("[AutoStart] An error occurred removing the auto start file.");
            }
        }
    }
    else
    {
        LOG_ERROR("Could not establish correct autostart file path.");
    }

    return(success);
}

bool AutoStart::EnableAutoStart(AutoStartInfo autostart_info)
{
    bool        success                             = false;

    /*-------------------------------------------------*\
    | Check if the filename is valid                    |
    \*-------------------------------------------------*/
    if(autostart_file != "")
    {
        std::string     desktop_file                = GenerateLaunchAgentFile(autostart_info);
        std::ofstream   autostart_file_stream(autostart_file, std::ios::out | std::ios::trunc);

        /*---------------------------------------------*\
        | Error out if the file could not be opened     |
        \*---------------------------------------------*/
        if(!autostart_file_stream)
        {
            LOG_ERROR("Could not open %s for writing.", autostart_file.c_str());
            success = false;
        }
        /*---------------------------------------------*\
        | Otherwise, write the file                     |
        \*---------------------------------------------*/
        else
        {
            autostart_file_stream << desktop_file;
            autostart_file_stream.close();
            success = !autostart_file_stream.fail();

            if (!success)
            {
                LOG_ERROR("An error occurred writing the auto start file.");
            }
        }
    }
    else
    {
        LOG_ERROR("Could not establish correct autostart file path.");
    }

    return(success);
}

bool AutoStart::IsAutoStartEnabled()
{
    /*-------------------------------------------------*\
    | Check if the filename is valid                    |
    \*-------------------------------------------------*/
    if(autostart_file != "")
    {
        return(filesystem::exists(autostart_file));
    }
    else
    {
        return(false);
    }
}

std::string AutoStart::GetExePath()
{
    /*-------------------------------------------------*\
    | Create the OpenRGB executable path                |
    \*-------------------------------------------------*/
    char     exepath[ PATH_MAX ];
    uint32_t exesize = PATH_MAX;

    int ret_val = _NSGetExecutablePath(exepath, &exesize);

    return(std::string(exepath, (ret_val == 0) ? strlen(exepath) : 0));

    return("");
}

/*-----------------------------------------------------*\
| MacOS AutoStart Implementation                        |
| Private Methods                                       |
\*-----------------------------------------------------*/

std::string AutoStart::GenerateLaunchAgentFile(AutoStartInfo autostart_info)
{
    /*-------------------------------------------------*\
    | Generate a .plist file from the AutoStart         |
    | parameters                                        |
    \*-------------------------------------------------*/
    std::stringstream fileContents;

    fileContents << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"                                                                    << std::endl;
    fileContents << "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"    << std::endl;
    fileContents << "<plist version=\"1.0\">"                                                                                       << std::endl;
    fileContents << "<dict>"                                                                                                        << std::endl;
    fileContents << "    <key>Label</key>"                                                                                          << std::endl;
    fileContents << "    <string>org.openrgb</string>"                                                                              << std::endl;
    fileContents << "    <key>ProgramArguments</key>"                                                                               << std::endl;
    fileContents << "    <array>"                                                                                                   << std::endl;
    fileContents << "        <string>" << autostart_info.path << "</string>"                                                        << std::endl;
    
    if(autostart_info.args != "")
    {
        std::istringstream arg_parser(autostart_info.args);
        std::string arg;

        while(arg_parser >> arg)
        {
            fileContents << "        <string>" << arg << "</string>"                                                                << std::endl;
        }
    }
    
    fileContents << "    </array>"                                                                                                  << std::endl;
    fileContents << "    <key>RunAtLoad</key><true/>"                                                                               << std::endl;
    fileContents << "</dict>"                                                                                                       << std::endl;
    fileContents << "</plist>"                                                                                                      << std::endl;
    
    return(fileContents.str());
}

void AutoStart::InitAutoStart(std::string name)
{
    std::string autostart_dir;

    autostart_name = name;

    /*-------------------------------------------------*\
    | Determine where the autostart .desktop files are  |
    | kept                                              |
    \*-------------------------------------------------*/
    autostart_dir = getenv("HOME");
    autostart_dir = autostart_dir + "/Library/LaunchAgents/";

    /*-------------------------------------------------*\
    | Check if the filename is valid                    |
    \*-------------------------------------------------*/
    if(autostart_dir != "")
    {
        std::error_code ec;

        bool success = true;
        
        if(!filesystem::exists(autostart_dir))
        {
            success = filesystem::create_directories(autostart_dir, ec);
        }

        if(success)
        {
            autostart_file = autostart_dir + autostart_name + ".plist";
        }
    }
}

