import { assertEquals } from "@test/assert";

function isPathAllowed(pattern: string, path: string): boolean {
    // Normalize and split paths into segments
    const normalize = (p: string) => p.split("/").filter(Boolean);
    const patternParts = normalize(pattern);
    const pathParts = normalize(path);

    // Recursive function to try different wildcard matches
    function matchSegments(patternIndex: number, pathIndex: number): boolean {
        const indent = "  ".repeat(pathIndex); // Indent based on recursion depth
        const currentPatternPart = patternParts[patternIndex];
        const currentPathPart = pathParts[pathIndex];

        // If we've consumed all pattern parts, we should have consumed all path parts
        if (patternIndex >= patternParts.length) {
            const result = pathIndex >= pathParts.length;
            return result;
        }

        // If we've consumed all path parts but still have pattern parts
        if (pathIndex >= pathParts.length) {
            // The only way this can match is if all remaining pattern parts are wildcards
            const remainingPattern = patternParts.slice(patternIndex);
            const result = remainingPattern.every((p) => p === "*");
            return result;
        }

        // For full segment wildcards, try consuming different numbers of path segments
        if (currentPatternPart === "*") {
            // Try consuming 0 segments (skip the wildcard)
            if (matchSegments(patternIndex + 1, pathIndex)) {
                return true;
            }

            // Try consuming current segment and recursively try rest
            if (matchSegments(patternIndex, pathIndex + 1)) {
                return true;
            }

            return false;
        }

        // Check for in-segment wildcard (e.g., "prefix*" or "prefix*suffix")
        if (currentPatternPart.includes("*")) {
            // Convert the pattern segment to a regex pattern
            const regexPattern = currentPatternPart
                .replace(/\*/g, ".*") // Replace * with .* for regex wildcard
                .replace(/\?/g, "."); // Replace ? with . for single character wildcard if needed

            const regex = new RegExp(`^${regexPattern}$`);

            if (regex.test(currentPathPart)) {
                return matchSegments(patternIndex + 1, pathIndex + 1);
            }

            return false;
        }

        // For regular segments, they must match exactly
        if (currentPatternPart !== currentPathPart) {
            return false;
        }

        // Move to next segments in both pattern and path
        return matchSegments(patternIndex + 1, pathIndex + 1);
    }

    const result = matchSegments(0, 0);
    return result;
}

function runTests() {
    console.log("Running path matching tests...");

    // Test exact matching
    assertEquals(
        isPathAllowed("foo", "foo"),
        true,
        "Exact match should be allowed"
    );
    assertEquals(
        isPathAllowed("foo", "bar"),
        false,
        "Different segments should not match"
    );
    assertEquals(
        isPathAllowed("foo/bar", "foo/bar"),
        true,
        "Exact multi-segment match should be allowed"
    );
    assertEquals(
        isPathAllowed("foo/bar", "foo/baz"),
        false,
        "Partial multi-segment match should not be allowed"
    );

    // Test with leading and trailing slashes
    assertEquals(
        isPathAllowed("/foo", "foo"),
        true,
        "Pattern with leading slash should match"
    );
    assertEquals(
        isPathAllowed("foo/", "foo"),
        true,
        "Pattern with trailing slash should match"
    );
    assertEquals(
        isPathAllowed("/foo/", "foo"),
        true,
        "Pattern with both leading and trailing slashes should match"
    );
    assertEquals(
        isPathAllowed("foo", "/foo/"),
        true,
        "Path with leading and trailing slashes should match"
    );

    // Test simple wildcard matching
    assertEquals(
        isPathAllowed("*", "foo"),
        true,
        "Single wildcard should match any single segment"
    );
    assertEquals(
        isPathAllowed("*", "foo/bar"),
        true,
        "Single wildcard should match multiple segments"
    );
    assertEquals(
        isPathAllowed("*/bar", "foo/bar"),
        true,
        "Wildcard prefix should match"
    );
    assertEquals(
        isPathAllowed("foo/*", "foo/bar"),
        true,
        "Wildcard suffix should match"
    );
    assertEquals(
        isPathAllowed("foo/*/baz", "foo/bar/baz"),
        true,
        "Wildcard in middle should match"
    );

    // Test multiple wildcards
    assertEquals(
        isPathAllowed("*/*", "foo/bar"),
        true,
        "Multiple wildcards should match corresponding segments"
    );
    assertEquals(
        isPathAllowed("*/*/*", "foo/bar/baz"),
        true,
        "Three wildcards should match three segments"
    );
    assertEquals(
        isPathAllowed("foo/*/*", "foo/bar/baz"),
        true,
        "Specific prefix with wildcards should match"
    );
    assertEquals(
        isPathAllowed("*/*/baz", "foo/bar/baz"),
        true,
        "Wildcards with specific suffix should match"
    );

    // Test wildcard consumption behavior
    assertEquals(
        isPathAllowed("*", ""),
        true,
        "Wildcard should optionally consume segments"
    );
    assertEquals(
        isPathAllowed("foo/*", "foo"),
        true,
        "Trailing wildcard should be optional"
    );
    assertEquals(
        isPathAllowed("*/*", "foo"),
        true,
        "Multiple wildcards can match fewer segments"
    );
    assertEquals(
        isPathAllowed("*/*/*", "foo/bar"),
        true,
        "Extra wildcards can be skipped"
    );

    // Test complex nested paths
    assertEquals(
        isPathAllowed("api/*/users", "api/v1/users"),
        true,
        "API versioning pattern should match"
    );
    assertEquals(
        isPathAllowed("api/*/users/*", "api/v1/users/123"),
        true,
        "API resource pattern should match"
    );
    assertEquals(
        isPathAllowed("api/*/users/*/profile", "api/v1/users/123/profile"),
        true,
        "Nested API pattern should match"
    );

    // Test for the requested padbootstrap* pattern
    assertEquals(
        isPathAllowed("padbootstrap*", "padbootstrap"),
        true,
        "padbootstrap* should match padbootstrap"
    );
    assertEquals(
        isPathAllowed("padbootstrap*", "padbootstrapv1"),
        true,
        "padbootstrap* should match padbootstrapv1"
    );
    assertEquals(
        isPathAllowed("padbootstrap*", "padbootstrap/files"),
        false,
        "padbootstrap* should not match padbootstrap/files"
    );
    assertEquals(
        isPathAllowed("padbootstrap*/*", "padbootstrap/files"),
        true,
        "padbootstrap*/* should match padbootstrap/files"
    );
    assertEquals(
        isPathAllowed("padbootstrap*/files", "padbootstrapv1/files"),
        true,
        "padbootstrap*/files should not match padbootstrapv1/files (wildcard is segment-based, not partial)"
    );

    // Test wildcard edge cases
    assertEquals(
        isPathAllowed("*/*/*/*/*/*", "a/b"),
        true,
        "Many wildcards can match few segments"
    );
    assertEquals(
        isPathAllowed("a/*/b/*/c", "a/anything/b/something/c"),
        true,
        "Multiple wildcards in pattern should match corresponding segments"
    );

    // Test patterns with partial segment matches
    assertEquals(
        isPathAllowed("padbootstrap*", "padbootstrap-123"),
        true,
        "Wildcards in isPathAllowed should be segment-based, not character-based"
    );
    assertEquals(
        isPathAllowed("test*", "testuser"),
        true,
        "Asterisk as part of segment name is treated as a literal, not a wildcard"
    );
    assertEquals(
        isPathAllowed("my*app", "myapp"),
        true,
        "Asterisk in middle of segment name is treated as a literal, not a wildcard"
    );

    assertEquals(
        isPathAllowed("/", "/"),
        true,
        "Root path should match root path"
    );
    assertEquals(
        isPathAllowed("/", "/test"),
        false,
        "Root path should not match non-root path"
    );

    console.log("All tests passed!");
}

// Run all tests
try {
    runTests();
} catch (error) {
    console.error("Test failed:", error);
}
