package de.softwareapp_hb.privateqrscanner.util

import de.softwareapp_hb.privateqrscanner.domain.UrlRiskResult
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test

class UrlRiskScorerTest {

    @Test
    fun `https domain has low risk`() {
        val result = UrlRiskScorer.score("https://example.com")
        assertEquals(0, result.score)
    }

    @Test
    fun `http adds two points`() {
        val result = UrlRiskScorer.score("http://example.com")
        assertEquals(2, result.score)
    }

    @Test
    fun `ip host adds two points`() {
        val result = UrlRiskScorer.score("https://93.184.216.34/path")
        assertEquals(2, result.score)
    }

    @Test
    fun `private ip host adds extra risk`() {
        val result = UrlRiskScorer.score("https://192.168.1.1/path")
        assertAtLeast(4, result.score)
        assertReasonContains(result, "private or reserved IP")
    }

    @Test
    fun `punycode host adds two points`() {
        val result = UrlRiskScorer.score("https://xn--pple-43d.com")
        assertAtLeast(2, result.score)
        assertReasonContains(result, "punycode")
    }

    @Test
    fun `long host adds one point`() {
        val result = UrlRiskScorer.score("https://averyveryveryveryveryveryveryverylonghostname.com")
        assertTrue(result.score >= 1)
    }

    @Test
    fun `long query adds one point`() {
        val query = "a".repeat(121)
        val result = UrlRiskScorer.score("https://example.com/?q=$query")
        assertEquals(1, result.score)
    }

    @Test
    fun `many percent encodings adds one point`() {
        val encoded = (1..11).joinToString("") { "%20" }
        val result = UrlRiskScorer.score("https://example.com/$encoded")
        assertEquals(1, result.score)
    }

    @Test
    fun `userinfo adds two points`() {
        val result = UrlRiskScorer.score("https://user:pass@example.com")
        assertEquals(2, result.score)
    }

    @Test
    fun `url shortener adds risk`() {
        val result = UrlRiskScorer.score("https://bit.ly/privateqr")
        assertAtLeast(2, result.score)
        assertReasonContains(result, "shortener")
    }

    @Test
    fun `non web scheme is high risk`() {
        val result = UrlRiskScorer.score("javascript:alert(1)")
        assertAtLeast(5, result.score)
        assertReasonContains(result, "unsafe URL scheme")
    }

    @Test
    fun `official brand login stays below warning threshold`() {
        val result = UrlRiskScorer.score("https://accounts.google.com/login")
        assertTrue(result.score < 3)
    }

    @Test
    fun `regional brand domain does not trigger impersonation heuristic`() {
        val result = UrlRiskScorer.score("https://google.de/login")
        assertTrue(result.score < 3)
    }

    @Test
    fun `brand embedded in unofficial host is risky`() {
        val result = UrlRiskScorer.score("https://paypal-security.example.com/login")
        assertAtLeast(3, result.score)
        assertReasonContains(result, "known brand")
    }

    @Test
    fun `lookalike brand host is risky`() {
        val result = UrlRiskScorer.score("https://paypa1.com")
        assertAtLeast(3, result.score)
        assertReasonContains(result, "resembles a known brand")
    }

    @Test
    fun `external redirect parameter is risky`() {
        val result = UrlRiskScorer.score("https://example.com/login?redirect=https%3A%2F%2Fevil.test")
        assertAtLeast(3, result.score)
        assertReasonContains(result, "redirects to another domain")
    }

    @Test
    fun `downloadable executable path is risky`() {
        val result = UrlRiskScorer.score("https://example.com/security-update.apk")
        assertAtLeast(3, result.score)
        assertReasonContains(result, "executable file")
    }

    @Test
    fun `combined risk can exceed threshold`() {
        val result = UrlRiskScorer.score("http://user:pass@192.168.0.1")
        assertTrue(result.score >= 6)
    }

    @Test
    fun `invalid url returns zero`() {
        val result = UrlRiskScorer.score("not a url")
        assertEquals(0, result.score)
    }

    @Test
    fun `reasons list is populated for risky urls`() {
        val result = UrlRiskScorer.score("http://xn--pple-43d.com")
        assertTrue(result.reasons.isNotEmpty())
    }

    private fun assertAtLeast(expectedMinimum: Int, actual: Int) {
        assertTrue("Expected score >= $expectedMinimum but was $actual", actual >= expectedMinimum)
    }

    private fun assertReasonContains(result: UrlRiskResult, text: String) {
        assertTrue(
            "Expected reasons to contain '$text' but were ${result.reasons}",
            result.reasons.any { it.contains(text, ignoreCase = true) }
        )
    }
}
