import std;

const std::vector<std::wstring_view> BAD_WORDS = {
    L"recovery",
    L"techie",
    L"http",
    L"https",
    L"digital",
    L"hack",
    L"::",
    L"//",
    L"com",
    L"@",
    L"crypto",
    L"bitcoin",
    L"wallet",
    L"hacker",
    L"welcome",
    L"whatsapp",
    L"email",
    L"cryptocurrency",
    L"stolen",
    L"freeze",
    L"quick",
    L"crucial",
    L"tracing",
    L"scammers",
    L"expers",
    L"hire",
    L"century",
    L"transaction",
    L"essential",
    L"managing",
    L"contact",
    L"contacting",
    L"understanding",
    L"assets",
    L"funds",
};


struct AnalysisResult {
    std::size_t totalWordCount = 0;
    std::size_t totalCapitalizedCount = 0;
    std::size_t totalSentenceCount = 0;
    std::size_t totalNumberCount = 0;
    std::size_t totalForbiddenCount = 0;

    operator std::string() const {
        return std::format(
            "Word Count: {}\nCapitalized Count: {}\nSentence Count: {}\nNumber Count: {}\nForbidden Count: {}",
            totalWordCount, totalCapitalizedCount, totalSentenceCount, totalNumberCount, totalForbiddenCount
            );
    }

    AnalysisResult operator+(const AnalysisResult &other) const {
        return {
            totalWordCount + other.totalWordCount,
            totalCapitalizedCount + other.totalCapitalizedCount,
            totalSentenceCount + other.totalSentenceCount,
            totalNumberCount + other.totalNumberCount,
            totalForbiddenCount + other.totalForbiddenCount
        };
    }
};

void check_word(const std::wstring &word, std::size_t &forbiddenCount) {
    if (std::find(BAD_WORDS.begin(), BAD_WORDS.end(), word) != BAD_WORDS.end()) {
        forbiddenCount++;
    }
}

AnalysisResult parseFile(const std::string_view &filename) {
    std::wifstream file;

    file.open(filename);
    if (!file.is_open()) {
        std::println("File doesn't exist: {}", filename);
        return { };
    }

    AnalysisResult result{ };

    bool inWord = false;
    wchar_t c;

    std::wstring word;
    while (file.get(c)) {
        if (c == '.') {
            result.totalSentenceCount++;
        }

        if (std::isspace(c) || c == '.' || c == '?' || c == '!' || c == ';' || c == ':') {
            inWord = false;

            check_word(word, result.totalForbiddenCount);
            word.clear();
            continue;
        } else {
            if (!inWord) {
                result.totalWordCount++;
                if (std::isupper(c)) {
                    result.totalCapitalizedCount++;
                }
            }
            inWord = true;

            if (std::isdigit(c)) {
                result.totalNumberCount++;
                while (file.get(c) && std::isdigit(c)) { }
                file.unget();
                continue;
            }

            word.push_back(c);
        }
    };

    if (!word.empty()) {
        check_word(word, result.totalForbiddenCount);
    }

    file.close();

    return result;
}

int main(const int argc, char *argv[]) {
    if (argc < 2) {
        std::println("Usage: {} <file1> <file2> ... <fileN>", argv[0]);
        return 1;
    }

    const AnalysisResult result = std::transform_reduce(std::execution::par, std::next(argv), argv + argc, AnalysisResult{ }, std::plus{ },
                                                        parseFile
        );

    std::println("{}", std::string(result));
    return 0;
}