package com.placeholder.sherpai2.data.local.entity

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
import org.json.JSONArray
import org.json.JSONObject
import java.util.UUID

/**
 * PersonEntity - ENHANCED with child tracking and sibling relationships
 */
@Entity(
    tableName = "persons",
    indices = [
        Index(value = ["name"]),
        Index(value = ["familyGroupId"])
    ]
)
data class PersonEntity(
    @PrimaryKey
    @ColumnInfo(name = "id")
    val id: String,

    @ColumnInfo(name = "name")
    val name: String,

    @ColumnInfo(name = "dateOfBirth")
    val dateOfBirth: Long?,

    @ColumnInfo(name = "isChild")
    val isChild: Boolean,              // NEW: Auto-set based on age

    @ColumnInfo(name = "siblingIds")
    val siblingIds: String?,           // NEW: JSON list ["uuid1", "uuid2"]

    @ColumnInfo(name = "familyGroupId")
    val familyGroupId: String?,        // NEW: UUID for family unit

    @ColumnInfo(name = "relationship")
    val relationship: String?,

    @ColumnInfo(name = "createdAt")
    val createdAt: Long,

    @ColumnInfo(name = "updatedAt")
    val updatedAt: Long
) {
    companion object {
        fun create(
            name: String,
            dateOfBirth: Long? = null,
            isChild: Boolean = false,
            siblingIds: List<String> = emptyList(),
            relationship: String? = null
        ): PersonEntity {
            val now = System.currentTimeMillis()

            // Create family group if siblings exist
            val familyGroupId = if (siblingIds.isNotEmpty()) {
                UUID.randomUUID().toString()
            } else null

            return PersonEntity(
                id = UUID.randomUUID().toString(),
                name = name,
                dateOfBirth = dateOfBirth,
                isChild = isChild,
                siblingIds = if (siblingIds.isNotEmpty()) {
                    JSONArray(siblingIds).toString()
                } else null,
                familyGroupId = familyGroupId,
                relationship = relationship,
                createdAt = now,
                updatedAt = now
            )
        }
    }

    fun getSiblingIds(): List<String> {
        return if (siblingIds != null) {
            try {
                val jsonArray = JSONArray(siblingIds)
                (0 until jsonArray.length()).map { jsonArray.getString(it) }
            } catch (e: Exception) {
                emptyList()
            }
        } else emptyList()
    }

    fun getAge(): Int? {
        if (dateOfBirth == null) return null
        val now = System.currentTimeMillis()
        val ageInMillis = now - dateOfBirth
        return (ageInMillis / (1000L * 60 * 60 * 24 * 365)).toInt()
    }

    fun getRelationshipEmoji(): String {
        return when (relationship) {
            "Family" -> "👨‍👩‍👧‍👦"
            "Friend" -> "🤝"
            "Partner" -> "❤️"
            "Child" -> "👶"
            "Parent" -> "👪"
            "Sibling" -> "👫"
            "Colleague" -> "💼"
            else -> "👤"
        }
    }
}

/**
 * FaceModelEntity - MULTI-CENTROID support for temporal tracking
 */
@Entity(
    tableName = "face_models",
    foreignKeys = [
        ForeignKey(
            entity = PersonEntity::class,
            parentColumns = ["id"],
            childColumns = ["personId"],
            onDelete = ForeignKey.CASCADE
        )
    ],
    indices = [Index(value = ["personId"], unique = true)]
)
data class FaceModelEntity(
    @PrimaryKey
    @ColumnInfo(name = "id")
    val id: String,

    @ColumnInfo(name = "personId")
    val personId: String,

    @ColumnInfo(name = "centroidsJson")
    val centroidsJson: String,         // NEW: List<TemporalCentroid> as JSON

    @ColumnInfo(name = "trainingImageCount")
    val trainingImageCount: Int,

    @ColumnInfo(name = "averageConfidence")
    val averageConfidence: Float,

    // Distribution stats for self-calibrating rejection
    @ColumnInfo(name = "similarityStdDev")
    val similarityStdDev: Float = 0.05f,  // Default for backwards compat

    @ColumnInfo(name = "similarityMin")
    val similarityMin: Float = 0.6f,      // Default for backwards compat

    @ColumnInfo(name = "createdAt")
    val createdAt: Long,

    @ColumnInfo(name = "updatedAt")
    val updatedAt: Long,

    @ColumnInfo(name = "lastUsed")
    val lastUsed: Long?,

    @ColumnInfo(name = "isActive")
    val isActive: Boolean
) {
    companion object {
        /**
         * Create with distribution stats for self-calibrating rejection
         */
        fun create(
            personId: String,
            embeddingArray: FloatArray,
            trainingImageCount: Int,
            averageConfidence: Float,
            similarityStdDev: Float = 0.05f,
            similarityMin: Float = 0.6f
        ): FaceModelEntity {
            return createFromEmbedding(personId, embeddingArray, trainingImageCount, averageConfidence, similarityStdDev, similarityMin)
        }

        /**
         * Create from single embedding with distribution stats
         */
        fun createFromEmbedding(
            personId: String,
            embeddingArray: FloatArray,
            trainingImageCount: Int,
            averageConfidence: Float,
            similarityStdDev: Float = 0.05f,
            similarityMin: Float = 0.6f
        ): FaceModelEntity {
            val now = System.currentTimeMillis()
            val centroid = TemporalCentroid(
                embedding = embeddingArray.toList(),
                effectiveTimestamp = now,
                ageAtCapture = null,
                photoCount = trainingImageCount,
                timeRangeMonths = 12,
                avgConfidence = averageConfidence
            )

            return FaceModelEntity(
                id = UUID.randomUUID().toString(),
                personId = personId,
                centroidsJson = serializeCentroids(listOf(centroid)),
                trainingImageCount = trainingImageCount,
                averageConfidence = averageConfidence,
                similarityStdDev = similarityStdDev,
                similarityMin = similarityMin,
                createdAt = now,
                updatedAt = now,
                lastUsed = null,
                isActive = true
            )
        }

        /**
         * Create from multiple centroids (temporal tracking)
         */
        fun createFromCentroids(
            personId: String,
            centroids: List<TemporalCentroid>,
            trainingImageCount: Int,
            averageConfidence: Float
        ): FaceModelEntity {
            val now = System.currentTimeMillis()
            return FaceModelEntity(
                id = UUID.randomUUID().toString(),
                personId = personId,
                centroidsJson = serializeCentroids(centroids),
                trainingImageCount = trainingImageCount,
                averageConfidence = averageConfidence,
                createdAt = now,
                updatedAt = now,
                lastUsed = null,
                isActive = true
            )
        }

        /**
         * Serialize list of centroids to JSON
         */
        private fun serializeCentroids(centroids: List<TemporalCentroid>): String {
            val jsonArray = JSONArray()
            centroids.forEach { centroid ->
                val jsonObj = JSONObject()
                jsonObj.put("embedding", JSONArray(centroid.embedding))
                jsonObj.put("effectiveTimestamp", centroid.effectiveTimestamp)
                jsonObj.put("ageAtCapture", centroid.ageAtCapture)
                jsonObj.put("photoCount", centroid.photoCount)
                jsonObj.put("timeRangeMonths", centroid.timeRangeMonths)
                jsonObj.put("avgConfidence", centroid.avgConfidence)
                jsonArray.put(jsonObj)
            }
            return jsonArray.toString()
        }

        /**
         * Deserialize JSON to list of centroids
         */
        private fun deserializeCentroids(json: String): List<TemporalCentroid> {
            val jsonArray = JSONArray(json)
            return (0 until jsonArray.length()).map { i ->
                val jsonObj = jsonArray.getJSONObject(i)
                val embeddingArray = jsonObj.getJSONArray("embedding")
                val embedding = (0 until embeddingArray.length()).map { j ->
                    embeddingArray.getDouble(j).toFloat()
                }
                TemporalCentroid(
                    embedding = embedding,
                    effectiveTimestamp = jsonObj.getLong("effectiveTimestamp"),
                    ageAtCapture = if (jsonObj.isNull("ageAtCapture")) null else jsonObj.getDouble("ageAtCapture").toFloat(),
                    photoCount = jsonObj.getInt("photoCount"),
                    timeRangeMonths = jsonObj.getInt("timeRangeMonths"),
                    avgConfidence = jsonObj.getDouble("avgConfidence").toFloat()
                )
            }
        }
    }

    fun getCentroids(): List<TemporalCentroid> {
        return try {
            FaceModelEntity.deserializeCentroids(centroidsJson)
        } catch (e: Exception) {
            emptyList()
        }
    }

    // Backwards compatibility: get first centroid as single embedding
    fun getEmbeddingArray(): FloatArray {
        val centroids = getCentroids()
        return if (centroids.isNotEmpty()) {
            centroids.first().getEmbeddingArray()
        } else {
            FloatArray(192) // Empty embedding
        }
    }
}

/**
 * TemporalCentroid - Represents a face appearance at a specific time period
 */
data class TemporalCentroid(
    val embedding: List<Float>,        // 192D vector
    val effectiveTimestamp: Long,      // Center of time window
    val ageAtCapture: Float?,          // Age in years (for children)
    val photoCount: Int,               // Number of photos in this cluster
    val timeRangeMonths: Int,          // Width of time window (e.g., 6 months)
    val avgConfidence: Float           // Quality indicator
) {
    fun getEmbeddingArray(): FloatArray = embedding.toFloatArray()
}

/**
 * PhotoFaceTagEntity - Unchanged
 */
@Entity(
    tableName = "photo_face_tags",
    foreignKeys = [
        ForeignKey(
            entity = ImageEntity::class,
            parentColumns = ["imageId"],
            childColumns = ["imageId"],
            onDelete = ForeignKey.CASCADE
        ),
        ForeignKey(
            entity = FaceModelEntity::class,
            parentColumns = ["id"],
            childColumns = ["faceModelId"],
            onDelete = ForeignKey.CASCADE
        )
    ],
    indices = [
        Index(value = ["imageId"]),
        Index(value = ["faceModelId"]),
        Index(value = ["imageId", "faceModelId"])
    ]
)
data class PhotoFaceTagEntity(
    @PrimaryKey
    @ColumnInfo(name = "id")
    val id: String,

    @ColumnInfo(name = "imageId")
    val imageId: String,

    @ColumnInfo(name = "faceModelId")
    val faceModelId: String,

    @ColumnInfo(name = "boundingBox")
    val boundingBox: String,

    @ColumnInfo(name = "confidence")
    val confidence: Float,

    @ColumnInfo(name = "embedding")
    val embedding: String,

    @ColumnInfo(name = "detectedAt")
    val detectedAt: Long,

    @ColumnInfo(name = "verifiedByUser")
    val verifiedByUser: Boolean,

    @ColumnInfo(name = "verifiedAt")
    val verifiedAt: Long?
) {
    companion object {
        fun create(
            imageId: String,
            faceModelId: String,
            boundingBox: android.graphics.Rect,
            confidence: Float,
            faceEmbedding: FloatArray
        ): PhotoFaceTagEntity {
            return PhotoFaceTagEntity(
                id = UUID.randomUUID().toString(),
                imageId = imageId,
                faceModelId = faceModelId,
                boundingBox = "${boundingBox.left},${boundingBox.top},${boundingBox.right},${boundingBox.bottom}",
                confidence = confidence,
                embedding = faceEmbedding.joinToString(","),
                detectedAt = System.currentTimeMillis(),
                verifiedByUser = false,
                verifiedAt = null
            )
        }
    }

    fun getBoundingBox(): android.graphics.Rect {
        val parts = boundingBox.split(",").map { it.toInt() }
        return android.graphics.Rect(parts[0], parts[1], parts[2], parts[3])
    }

    fun getEmbeddingArray(): FloatArray {
        return embedding.split(",").map { it.toFloat() }.toFloatArray()
    }
}

/**
 * PersonAgeTagEntity - NEW: Searchable age tags
 */
@Entity(
    tableName = "person_age_tags",
    foreignKeys = [
        ForeignKey(
            entity = PersonEntity::class,
            parentColumns = ["id"],
            childColumns = ["personId"],
            onDelete = ForeignKey.CASCADE
        ),
        ForeignKey(
            entity = ImageEntity::class,
            parentColumns = ["imageId"],
            childColumns = ["imageId"],
            onDelete = ForeignKey.CASCADE
        )
    ],
    indices = [
        Index(value = ["personId"]),
        Index(value = ["imageId"]),
        Index(value = ["ageAtCapture"]),
        Index(value = ["tagValue"])
    ]
)
data class PersonAgeTagEntity(
    @PrimaryKey
    @ColumnInfo(name = "id")
    val id: String,

    @ColumnInfo(name = "personId")
    val personId: String,

    @ColumnInfo(name = "imageId")
    val imageId: String,

    @ColumnInfo(name = "ageAtCapture")
    val ageAtCapture: Int,

    @ColumnInfo(name = "tagValue")
    val tagValue: String,             // e.g., "emma_age3"

    @ColumnInfo(name = "confidence")
    val confidence: Float,

    @ColumnInfo(name = "createdAt")
    val createdAt: Long
) {
    companion object {
        fun create(
            personId: String,
            personName: String,
            imageId: String,
            ageAtCapture: Int,
            confidence: Float
        ): PersonAgeTagEntity {
            return PersonAgeTagEntity(
                id = UUID.randomUUID().toString(),
                personId = personId,
                imageId = imageId,
                ageAtCapture = ageAtCapture,
                tagValue = "${personName.lowercase().replace(" ", "_")}_age$ageAtCapture",
                confidence = confidence,
                createdAt = System.currentTimeMillis()
            )
        }
    }
}