// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Wildcard Matcher Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "WildcardMatcher.h"
#include <iomanip>
#include <algorithm>

/**
 * @brief Default constructor
 */
WildcardMatcher::WildcardMatcher() : mRecursionCount(0), mBacktrackCount(0), mDPTableSize(0) {
}

/**
 * @brief Destructor
 */
WildcardMatcher::~WildcardMatcher() {
}

/**
 * @brief Main matching function using dynamic programming approach
 * @param text The input string to match
 * @param pattern The wildcard pattern
 * @return true if text matches pattern, false otherwise
 */
bool WildcardMatcher::IsMatch(const std::string& text, const std::string& pattern) {
    ResetCounters();
    
    if (!IsValidPattern(pattern)) {
        std::cerr << "Error: Invalid pattern provided" << std::endl;
        return false;
    }
    
    // Use dynamic programming for better performance
    return IsMatchDP(text, pattern);
}

/**
 * @brief Dynamic programming approach for wildcard matching
 * @param text The input string to match
 * @param pattern The wildcard pattern
 * @return true if text matches pattern, false otherwise
 */
bool WildcardMatcher::IsMatchDP(const std::string& text, const std::string& pattern) {
    int textLen = text.length();
    int patternLen = pattern.length();
    
    // Preprocess pattern to remove consecutive '*' characters
    std::string processedPattern = PreprocessPattern(pattern);
    patternLen = processedPattern.length();
    
    // Create DP table
    std::vector<std::vector<bool>> dp(textLen + 1, std::vector<bool>(patternLen + 1, false));
    mDPTableSize = (textLen + 1) * (patternLen + 1);
    
    // Base case: empty pattern matches empty text
    dp[0][0] = true;
    
    // Handle patterns starting with '*'
    for (int j = 1; j <= patternLen; j++) {
        if (processedPattern[j - 1] == WILDCARD_MULTI) {
            dp[0][j] = dp[0][j - 1];
        }
    }
    
    // Fill the DP table
    for (int i = 1; i <= textLen; i++) {
        for (int j = 1; j <= patternLen; j++) {
            char textChar = text[i - 1];
            char patternChar = processedPattern[j - 1];
            
            if (patternChar == WILDCARD_MULTI) {
                // '*' can match empty sequence or any character
                dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
            } else if (patternChar == WILDCARD_SINGLE || patternChar == textChar) {
                // '?' matches any character, or exact character match
                dp[i][j] = dp[i - 1][j - 1];
            }
            // else: no match, dp[i][j] remains false
        }
    }
    
    return dp[textLen][patternLen];
}

/**
 * @brief Recursive backtracking approach for wildcard matching
 * @param text The input string to match
 * @param pattern The wildcard pattern
 * @return true if text matches pattern, false otherwise
 */
bool WildcardMatcher::IsMatchRecursive(const std::string& text, const std::string& pattern) {
    ResetCounters();
    
    if (!IsValidPattern(pattern)) {
        std::cerr << "Error: Invalid pattern provided" << std::endl;
        return false;
    }
    
    std::string processedPattern = PreprocessPattern(pattern);
    return IsMatchRecursiveHelper(text, processedPattern, 0, 0);
}

/**
 * @brief Recursive helper function for pattern matching
 * @param text The input string
 * @param pattern The wildcard pattern
 * @param textIdx Current index in text
 * @param patternIdx Current index in pattern
 * @return true if remaining text matches remaining pattern
 */
bool WildcardMatcher::IsMatchRecursiveHelper(const std::string& text, const std::string& pattern,
                                           int textIdx, int patternIdx) {
    mRecursionCount++;
    
    // Base cases
    if (patternIdx == pattern.length()) {
        return textIdx == text.length();
    }
    
    if (textIdx == text.length()) {
        // Check if remaining pattern consists only of '*'
        for (int i = patternIdx; i < pattern.length(); i++) {
            if (pattern[i] != WILDCARD_MULTI) {
                return false;
            }
        }
        return true;
    }
    
    char textChar = text[textIdx];
    char patternChar = pattern[patternIdx];
    
    if (patternChar == WILDCARD_MULTI) {
        // Try matching '*' with empty sequence
        if (IsMatchRecursiveHelper(text, pattern, textIdx, patternIdx + 1)) {
            return true;
        }
        
        // Try matching '*' with one or more characters
        if (IsMatchRecursiveHelper(text, pattern, textIdx + 1, patternIdx)) {
            return true;
        }
        
        mBacktrackCount++;
        return false;
    } else if (patternChar == WILDCARD_SINGLE || patternChar == textChar) {
        // '?' matches any character, or exact character match
        return IsMatchRecursiveHelper(text, pattern, textIdx + 1, patternIdx + 1);
    } else {
        // No match
        mBacktrackCount++;
        return false;
    }
}

/**
 * @brief Validates if the pattern contains only valid wildcard characters
 * @param pattern The pattern to validate
 * @return true if valid, false otherwise
 */
bool WildcardMatcher::IsValidPattern(const std::string& pattern) const {
    // For wildcard matching, all characters are valid
    // This could be extended to check for specific constraints if needed
    return true;
}

/**
 * @brief Preprocesses pattern to optimize matching by removing consecutive '*'
 * @param pattern The original pattern
 * @return Optimized pattern with consecutive '*' merged
 */
std::string WildcardMatcher::PreprocessPattern(const std::string& pattern) const {
    if (pattern.empty()) {
        return pattern;
    }
    
    std::string result;
    result.reserve(pattern.length());
    
    char prev = '\0';
    for (char c : pattern) {
        if (c != WILDCARD_MULTI || prev != WILDCARD_MULTI) {
            result += c;
        }
        prev = c;
    }
    
    return result;
}

/**
 * @brief Prints the matching result in a formatted manner
 * @param text The input text
 * @param pattern The wildcard pattern
 * @param result The matching result
 */
void WildcardMatcher::PrintMatchResult(const std::string& text, const std::string& pattern, bool result) const {
    std::cout << "\n" << std::string(50, '=') << std::endl;
    std::cout << "Wildcard Matching Result:" << std::endl;
    std::cout << std::string(50, '=') << std::endl;
    
    std::cout << "Text:    \"" << text << "\"" << std::endl;
    std::cout << "Pattern: \"" << pattern << "\"" << std::endl;
    std::cout << "Result:  " << (result ? "MATCH" : "NO MATCH") << std::endl;
    
    std::cout << "\nStatistics:" << std::endl;
    std::cout << "- Recursions: " << mRecursionCount << std::endl;
    std::cout << "- Backtracks: " << mBacktrackCount << std::endl;
    std::cout << "- DP Table Size: " << mDPTableSize << std::endl;
    
    std::cout << std::string(50, '=') << std::endl;
}

/**
 * @brief Runs comprehensive tests for the wildcard matcher
 */
void WildcardMatcher::RunTests() {
    std::cout << "\n🧪 Running Wildcard Matcher Tests..." << std::endl;
    std::cout << std::string(60, '=') << std::endl;
    
    // Test cases from LeetCode problem 44
    std::vector<std::pair<std::pair<std::string, std::string>, bool>> testCases = {
        {{"aa", "a"}, false},
        {{"aa", "*"}, true},
        {{"cb", "?a"}, false},
        {{"adceb", "*a*b*"}, true},
        {{"acdcb", "a*c?b"}, false},
        {{"", "*"}, true},
        {{"", ""}, true},
        {{"a", ""}, false},
        {{"abcdef", "a*f"}, true},
        {{"abcdef", "a*g"}, false},
        {{"mississippi", "m*iss*iss*pi"}, true},
        {{"ho", "ho**"}, true},
        {{"abcabczzzde", "*abc???de*"}, true}
    };
    
    int passed = 0;
    int total = testCases.size();
    
    for (size_t i = 0; i < testCases.size(); i++) {
        const std::string& text = testCases[i].first.first;
        const std::string& pattern = testCases[i].first.second;
        bool expected = testCases[i].second;
        
        bool result = IsMatch(text, pattern);
        bool testPassed = (result == expected);
        
        std::cout << "Test " << (i + 1) << ": ";
        std::cout << "\"" << text << "\" vs \"" << pattern << "\" -> ";
        std::cout << (result ? "MATCH" : "NO MATCH");
        std::cout << " [" << (testPassed ? "PASS" : "FAIL") << "]" << std::endl;
        
        if (testPassed) {
            passed++;
        } else {
            std::cout << "  Expected: " << (expected ? "MATCH" : "NO MATCH") << std::endl;
        }
    }
    
    std::cout << std::string(60, '=') << std::endl;
    std::cout << "Tests Passed: " << passed << "/" << total << std::endl;
    std::cout << "Success Rate: " << std::fixed << std::setprecision(1) 
              << (100.0 * passed / total) << "%" << std::endl;
}

/**
 * @brief Resets the recursion and backtrack counters
 */
void WildcardMatcher::ResetCounters() {
    mRecursionCount = 0;
    mBacktrackCount = 0;
    mDPTableSize = 0;
}

/**
 * @brief Prints debug information during recursive matching
 * @param text The input text
 * @param pattern The pattern
 * @param textIdx Current text index
 * @param patternIdx Current pattern index
 * @param action Description of current action
 */
void WildcardMatcher::PrintDebugInfo(const std::string& text, const std::string& pattern,
                                   int textIdx, int patternIdx, const std::string& action) const {
    std::cout << "Debug: " << action << " - Text[" << textIdx << "], Pattern[" << patternIdx << "]" << std::endl;
}