package com.tt.honeyDue.ui.design

import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue

/**
 * Tests for organic design primitives ported from iOS OrganicDesign.swift.
 *
 * These tests are deterministic — they verify that the same input produces
 * the same geometry so UI snapshot regressions and cross-platform parity
 * can be asserted without rendering.
 */
class OrganicDesignTest {

    // ---------------------------------------------------------------------
    // Determinism: same seed + size → identical path
    // ---------------------------------------------------------------------

    @Test
    fun blobShapeIsDeterministicForSameSeedAndSize() {
        val size = Size(100f, 100f)
        val a = BlobShape.serializePath(size = size, variation = 0, seed = 42L)
        val b = BlobShape.serializePath(size = size, variation = 0, seed = 42L)
        assertEquals(a, b, "BlobShape must produce identical paths for identical inputs")
        assertTrue(a.isNotEmpty(), "Serialized path must not be empty")
    }

    @Test
    fun blobShapeIsDeterministicAcrossMultipleInvocations() {
        val size = Size(256f, 128f)
        val runs = List(5) {
            BlobShape.serializePath(size = size, variation = 1, seed = 7L)
        }
        val first = runs.first()
        runs.forEach { assertEquals(first, it) }
    }

    // ---------------------------------------------------------------------
    // Variations: N distinct shapes, matching iOS OrganicBlobShape count
    // ---------------------------------------------------------------------

    @Test
    fun blobShapeHasExpectedVariationCountMatchingIos() {
        // iOS OrganicBlobShape switches on variation % 3 (cloud / pebble / leaf).
        assertEquals(3, BlobShape.VARIATION_COUNT)
    }

    @Test
    fun blobShapeVariationsProduceDistinctPaths() {
        val size = Size(200f, 200f)
        val paths = (0 until BlobShape.VARIATION_COUNT).map { v ->
            BlobShape.serializePath(size = size, variation = v, seed = 0L)
        }
        // Every pair must differ.
        for (i in paths.indices) {
            for (j in i + 1 until paths.size) {
                assertNotEquals(
                    paths[i],
                    paths[j],
                    "variation $i and $j must produce distinct paths"
                )
            }
        }
    }

    @Test
    fun blobShapeVariationIndexWrapsModulo() {
        val size = Size(100f, 100f)
        val base = BlobShape.serializePath(size = size, variation = 0, seed = 0L)
        val wrapped = BlobShape.serializePath(
            size = size,
            variation = BlobShape.VARIATION_COUNT,
            seed = 0L
        )
        assertEquals(base, wrapped, "variation index must wrap modulo VARIATION_COUNT")
    }

    @Test
    fun blobShapeDifferentSeedsProduceDifferentPaths() {
        val size = Size(100f, 100f)
        val a = BlobShape.serializePath(size = size, variation = 0, seed = 1L)
        val b = BlobShape.serializePath(size = size, variation = 0, seed = 2L)
        assertNotEquals(a, b, "different seeds must perturb the path")
    }

    // ---------------------------------------------------------------------
    // RadialGlow: parameter API surface (not a pixel test)
    // ---------------------------------------------------------------------

    @Test
    fun radialGlowParamsExposesColorCenterAndRadius() {
        val params = RadialGlowParams(
            color = Color.Red,
            center = Offset(10f, 20f),
            radius = 50f
        )
        assertEquals(Color.Red, params.color)
        assertEquals(Offset(10f, 20f), params.center)
        assertEquals(50f, params.radius)
    }

    @Test
    fun radialGlowParamsEqualityIsValueBased() {
        val a = RadialGlowParams(Color.Blue, Offset(1f, 2f), 3f)
        val b = RadialGlowParams(Color.Blue, Offset(1f, 2f), 3f)
        assertEquals(a, b)
    }

    // ---------------------------------------------------------------------
    // OrganicRadius: constants match iOS point-values
    // ---------------------------------------------------------------------

    @Test
    fun organicRadiusConstantsMatchIosValues() {
        // iOS AppRadius (points == dp):
        // xs 4, sm 8, md 12, lg 16, xl 20, xxl 24, full 9999
        // iOS OrganicRoundedRectangle default cornerRadius == 28 → blob.
        assertEquals(4.dp, OrganicRadius.xs)
        assertEquals(8.dp, OrganicRadius.sm)
        assertEquals(12.dp, OrganicRadius.md)
        assertEquals(16.dp, OrganicRadius.lg)
        assertEquals(20.dp, OrganicRadius.xl)
        assertEquals(28.dp, OrganicRadius.blob)
    }

    // ---------------------------------------------------------------------
    // OrganicSpacing: matches iOS OrganicSpacing (compact/cozy/…)
    // ---------------------------------------------------------------------

    @Test
    fun organicSpacingConstantsMatchIosValues() {
        // iOS OrganicSpacing:
        //   compact 8, cozy 20, comfortable 24, spacious 32, airy 40
        assertEquals(8.dp, OrganicSpacing.compact)
        assertEquals(20.dp, OrganicSpacing.cozy)
        assertEquals(24.dp, OrganicSpacing.comfortable)
        assertEquals(32.dp, OrganicSpacing.spacious)
        assertEquals(40.dp, OrganicSpacing.airy)
    }

    // ---------------------------------------------------------------------
    // Honeycomb overlay: configuration exposes tile size + color + opacity
    // ---------------------------------------------------------------------

    @Test
    fun honeycombOverlayConfigDefaultsMatchIos() {
        // iOS HoneycombTextureCache: tile 60 x 103.92, stroke #C4856A, 0.8pt.
        val cfg = HoneycombOverlayConfig()
        assertEquals(60f, cfg.tileWidth)
        assertEquals(103.92f, cfg.tileHeight)
        // #C4856A opaque — iOS honeycomb stroke color.
        assertEquals(Color(0xFFC4856A), cfg.strokeColor)
        assertEquals(0.8f, cfg.strokeWidth)
        assertEquals(0.10f, cfg.opacity)
    }
}
