/*
 * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License v2 as published by the
 * Free Software Foundation.
 */

#include "EncounterJournalMgr.h"

#include "Chat.h"
#include "CommandScript.h"

#include <string>
#include <vector>

using namespace Acore::ChatCommands;

class encounter_journal_commandscript : public CommandScript
{
public:
    encounter_journal_commandscript() : CommandScript("encounter_journal_commandscript") { }

    ChatCommandTable GetCommands() const override
    {
        static ChatCommandTable ejCommandTable =
        {
            { "reload",         HandleReloadCommand,         SEC_ADMINISTRATOR, Console::Yes },
            { "export",         HandleExportCommand,         SEC_ADMINISTRATOR, Console::Yes },
            { "validate",       HandleValidateCommand,       SEC_ADMINISTRATOR, Console::Yes },
            { "importloot",     HandleImportLootCommand,     SEC_ADMINISTRATOR, Console::Yes },
            { "importskeleton", HandleImportSkeletonCommand, SEC_ADMINISTRATOR, Console::Yes },
            { "importall",      HandleImportAllCommand,      SEC_ADMINISTRATOR, Console::Yes },
            { "info",           HandleInfoCommand,           SEC_GAMEMASTER,    Console::Yes },
        };

        static ChatCommandTable commandTable =
        {
            { "ej", ejCommandTable },
        };
        return commandTable;
    }

    static bool HandleReloadCommand(ChatHandler* handler)
    {
        sEncounterJournalMgr->Load();
        handler->PSendSysMessage("Encounter Journal reloaded ({} instances, "
            "{} encounters, {} sections, {} loot rows).",
            sEncounterJournalMgr->InstanceCount(),
            sEncounterJournalMgr->EncounterCount(),
            sEncounterJournalMgr->SectionCount(),
            sEncounterJournalMgr->LootCount());
        return true;
    }

    static bool HandleExportCommand(ChatHandler* handler)
    {
        sEncounterJournalMgr->Load();

        std::vector<std::string> paths;
        std::string error;
        if (!sEncounterJournalMgr->Export(paths, error))
        {
            handler->SendErrorMessage("Encounter Journal export failed: {}", error);
            return false;
        }

        handler->PSendSysMessage("Encounter Journal exported {} file(s):", paths.size());
        for (std::string const& p : paths)
            handler->PSendSysMessage("  {}", p);
        return true;
    }

    static bool HandleValidateCommand(ChatHandler* handler)
    {
        sEncounterJournalMgr->Load();

        std::vector<std::string> errors;
        std::size_t count = sEncounterJournalMgr->Validate(errors);
        if (count == 0)
        {
            handler->PSendSysMessage("Encounter Journal: validation OK "
                "({} instances, {} encounters, {} sections, {} loot rows).",
                sEncounterJournalMgr->InstanceCount(),
                sEncounterJournalMgr->EncounterCount(),
                sEncounterJournalMgr->SectionCount(),
                sEncounterJournalMgr->LootCount());
            return true;
        }

        handler->PSendSysMessage("Encounter Journal: {} issue(s):", count);
        // Cap output to avoid flooding chat in the in-game case.
        std::size_t const limit = 50;
        for (std::size_t i = 0; i < errors.size() && i < limit; ++i)
            handler->PSendSysMessage("  {}", errors[i]);
        if (errors.size() > limit)
            handler->PSendSysMessage("  ... and {} more (run from console for full list)",
                errors.size() - limit);
        return true;
    }

    static bool HandleImportLootCommand(ChatHandler* handler)
    {
        sEncounterJournalMgr->Load();

        std::vector<std::string> warnings;
        std::size_t inserted = sEncounterJournalMgr->ImportLoot(warnings);

        handler->PSendSysMessage(
            "Encounter Journal loot import: inserted {} row(s).", inserted);
        if (!warnings.empty())
        {
            handler->PSendSysMessage("{} warning(s):", warnings.size());
            std::size_t const limit = 25;
            for (std::size_t i = 0; i < warnings.size() && i < limit; ++i)
                handler->PSendSysMessage("  {}", warnings[i]);
            if (warnings.size() > limit)
                handler->PSendSysMessage("  ... and {} more",
                    warnings.size() - limit);
        }
        if (inserted > 0)
            handler->PSendSysMessage("Reload the manager (.ej reload) to "
                "see the new rows in subsequent .ej export/validate.");
        return true;
    }

    static bool HandleImportSkeletonCommand(ChatHandler* handler)
    {
        sEncounterJournalMgr->Load();

        MoonWell::EncounterJournal::Mgr::SkeletonCounts c;
        std::vector<std::string> warnings;
        std::size_t total = sEncounterJournalMgr->ImportSkeleton(c, warnings);

        handler->PSendSysMessage(
            "Encounter Journal skeleton import: {} new rows.", total);
        handler->PSendSysMessage(
            "  tiers={}  instances={}  tier_instances={}",
            c.tiers, c.instances, c.tierInstances);
        handler->PSendSysMessage(
            "  encounters={}  creatures={}  sections={}",
            c.encounters, c.creatures, c.sections);

        if (!warnings.empty())
        {
            handler->PSendSysMessage("{} warning(s):", warnings.size());
            std::size_t const limit = 25;
            for (std::size_t i = 0; i < warnings.size() && i < limit; ++i)
                handler->PSendSysMessage("  {}", warnings[i]);
            if (warnings.size() > limit)
                handler->PSendSysMessage("  ... and {} more",
                    warnings.size() - limit);
        }
        if (total > 0)
            handler->PSendSysMessage("Run .ej importloot next, then .ej export.");
        return true;
    }

    static bool HandleImportAllCommand(ChatHandler* handler)
    {
        HandleImportSkeletonCommand(handler);
        sEncounterJournalMgr->Load();
        return HandleImportLootCommand(handler);
    }

    static bool HandleInfoCommand(ChatHandler* handler)
    {
        handler->PSendSysMessage("Encounter Journal cache:");
        handler->PSendSysMessage("  tiers:      {}", sEncounterJournalMgr->TierCount());
        handler->PSendSysMessage("  instances:  {}", sEncounterJournalMgr->InstanceCount());
        handler->PSendSysMessage("  encounters: {}", sEncounterJournalMgr->EncounterCount());
        handler->PSendSysMessage("  creatures:  {}", sEncounterJournalMgr->CreatureCount());
        handler->PSendSysMessage("  sections:   {}", sEncounterJournalMgr->SectionCount());
        handler->PSendSysMessage("  loot rows:  {}", sEncounterJournalMgr->LootCount());
        return true;
    }
};

void AddSC_encounter_journal_commands()
{
    new encounter_journal_commandscript();
}
