@testable import DeeplinkIntents
import Foundation
import Testing

@Suite("DeeplinkIntent Tests")
struct DeeplinkIntentTests {
    private func makeDeepLink(url: URL) -> DeeplinkIntent? {
        DeeplinkIntent(url: url, forceV2: true)
    }

    @Test func testValidSchemesAndHosts() {
        var url: URL!

        // Valid
        url = URL(string: "suno://song/123")!
        #expect(makeDeepLink(url: url) != nil)

        url = URL(string: "http://suno.com/song/123")!
        #expect(makeDeepLink(url: url) != nil)

        url = URL(string: "https://www.suno.com/song/123")!
        #expect(makeDeepLink(url: url) != nil)

        url = URL(string: "suno.com/song/123")!
        #expect(makeDeepLink(url: url) != nil)

        url = URL(string: "www.suno.com/notifications")!
        #expect(makeDeepLink(url: url) != nil)

        url = URL(string: "suno.com/s/someId")!
        #expect(makeDeepLink(url: url) != nil)

        url = URL(string: "https://suno.com/@ramikay")!
        #expect(makeDeepLink(url: url) != nil)

        // Invalid
        url = URL(string: "otherapp://song/123")!
        #expect(makeDeepLink(url: url) == nil)

        url = URL(string: "https://otherapp.com/song/123")!
        #expect(makeDeepLink(url: url) == nil)

        url = URL(string: "ftp://suno.com/song/123")!
        #expect(makeDeepLink(url: url) == nil)

        url = URL(string: "https://endswithsuno.com/song/123")!
        #expect(makeDeepLink(url: url) == nil)
    }

    @Test func testInAppLinkGeneration() {
        let isEqual: (String, DeeplinkIntent) -> Bool = { string, intent in
            Bundle.main.makeInAppURL(for: intent)?.absoluteString == string
        }

        #expect(isEqual("suno://library", .library))
        #expect(isEqual("suno://create", .create))
        #expect(isEqual("suno://create-text", .createText))
        #expect(isEqual("suno://create-audio", .createAudio))
        #expect(isEqual("suno://create-camera", .createCamera))
        #expect(isEqual("suno://notifications", .notifications))
        #expect(isEqual("suno://song/123", .song(songId: "123", sh: nil)))
        #expect(isEqual("suno://song/123?sh=abc", .song(songId: "123", sh: "abc")))
        #expect(isEqual("suno://remix?song_id=123&type=type&style=style&lyrics=lyrics", .remix(songId: "123", type: "type", style: "style", lyrics: "lyrics")))
        #expect(isEqual("suno://hooks", .hooks))
    }

    @Test func testSongLinks() {
        var url: URL!

        // suno:// URL Scheme
        url = URL(string: "suno://song/123")!
        #expect(makeDeepLink(url: url) == .song(songId: "123", sh: nil))

        url = URL(string: "suno://song/123?sh=abc")!
        #expect(makeDeepLink(url: url) == .song(songId: "123", sh: "abc"))

        // suno.com
        url = URL(string: "https://suno.com/song/123")!
        #expect(makeDeepLink(url: url) == .song(songId: "123", sh: nil))

        url = URL(string: "https://suno.com/song/123?sh=abc")!
        #expect(makeDeepLink(url: url) == .song(songId: "123", sh: "abc"))

        url = URL(string: "www.suno.com/song/123?sh=abc")!
        #expect(makeDeepLink(url: url) == .song(songId: "123", sh: "abc"))

        url = URL(string: "suno.com/song/123?sh=abc")!
        #expect(makeDeepLink(url: url) == .song(songId: "123", sh: "abc"))

        // Exotic cases
        url = URL(string: "suno://song")!
        #expect(makeDeepLink(url: url) == nil)

        url = URL(string: "suno://song/?sh=abc")!
        #expect(makeDeepLink(url: url) == nil)

        url = URL(string: "suno://?song=123")!
        #expect(makeDeepLink(url: url) == nil)

        url = URL(string: "https://suno.com/song")!
        #expect(makeDeepLink(url: url) == nil)

        url = URL(string: "https://suno.com/song?sh=abc")!
        #expect(makeDeepLink(url: url) == nil)

        url = URL(string: "https://suno.com/song=123")!
        #expect(makeDeepLink(url: url) == nil)
    }

    @Test func testLibraryLinks() {
        var url: URL!

        url = URL(string: "suno://library")!
        #expect(makeDeepLink(url: url) == .library)

        url = URL(string: "https://suno.com/me")!
        #expect(makeDeepLink(url: url) == .library)
    }

    @Test func testShortCodes() {
        var url: URL!

        url = URL(string: "https://suno.com/s/someId")!
        #expect(makeDeepLink(url: url) == .contentShortlink(shortcode: "someId"))

        url = URL(string: "http://suno.com/s/anotherId")!
        #expect(makeDeepLink(url: url) == .contentShortlink(shortcode: "anotherId"))

        url = URL(string: "suno.com/s/yetAnother")!
        #expect(makeDeepLink(url: url) == .contentShortlink(shortcode: "yetAnother"))

        url = URL(string: "suno://s/thisToo")!
        #expect(makeDeepLink(url: url) == .contentShortlink(shortcode: "thisToo"))
    }

    @Test func testAlternateHandleFormate() {
        var url: URL!

        url = URL(string: "https://suno.com/@ramikay")!
        #expect(makeDeepLink(url: url) == .profile(profileId: "ramikay"))
    }

    @Test func testRemixLinks() {
        var url: URL!

        url = URL(string: "suno://remix?song_id=123&type=type&style=style&lyrics=lyrics")!
        #expect(makeDeepLink(url: url) == .remix(songId: "123", type: "type", style: "style", lyrics: "lyrics"))

        // Missing a `song_id` is considered undefined behavior
        url = URL(string: "suno://remix?type=type&style=style&lyrics=lyrics")!
        #expect(makeDeepLink(url: url) == nil)
    }

    // FIXME: These tests will fail as they are gated by FeatureFlag.hooks.isFeedEnabled which is false by default
    // Removing them for now for our release.
    /*
    @Test func testHooksLinks() {
        var url: URL!

        // Test hooks deeplink parsing
        url = URL(string: "https://suno.com/hooks")!
        #expect(makeDeepLink(url: url) == .hooks)

        url = URL(string: "http://suno.com/hooks")!
        #expect(makeDeepLink(url: url) == .hooks)

        url = URL(string: "www.suno.com/hooks")!
        #expect(makeDeepLink(url: url) == .hooks)

        url = URL(string: "suno.com/hooks")!
        #expect(makeDeepLink(url: url) == .hooks)

        url = URL(string: "suno://hooks")!
        #expect(makeDeepLink(url: url) == .hooks)

        // Test invalid hooks URLs
        url = URL(string: "https://suno.com/hooks/extra")!
        #expect(makeDeepLink(url: url) == nil)

        url = URL(string: "https://suno.com/hook")!
        #expect(makeDeepLink(url: url) == nil)

        url = URL(string: "https://suno.com/hook/123")!
        #expect(makeDeepLink(url: url) == .hook(hookId: "123"))
    }
    */

    // FIXME: These tests will fail as they are gated by FeatureFlag.hooks.isFeedEnabled which is false by default
    // Removing them for now for our release.
    @Test func testProfileHookLinks() {
        var url: URL!

        // Test profile hook parsing
//        url = URL(string: "https://suno.com/@asadrzv/hook/7cda5593-ef10-40de-89a2-75178e0e5949")!
//        #expect(makeDeepLink(url: url) == .profileHook(userHandle: "asadrzv", hookId: "7cda5593-ef10-40de-89a2-75178e0e5949"))
//
//        url = URL(string: "https://www.suno.com/@username/hook/123")!
//        #expect(makeDeepLink(url: url) == .profileHook(userHandle: "username", hookId: "123"))
//
//        url = URL(string: "suno.com/@testuser/hook/abc-def")!
//        #expect(makeDeepLink(url: url) == .profileHook(userHandle: "testuser", hookId: "abc-def"))

        // Test that simple profile paths still work
        url = URL(string: "https://suno.com/@asadrzv")!
        #expect(makeDeepLink(url: url) == .profile(profileId: "asadrzv"))
    }
}
