package com.rera.mss.model

import com.rera.mss.config.MEDIUM_STRING_FIELD_LENGTH
import com.rera.mss.config.SHORT_STRING_FIELD_LENGTH
import org.hibernate.annotations.NaturalId
import javax.persistence.*
import javax.validation.constraints.NotBlank
import javax.validation.constraints.Size

@Entity
@Table(name = "Instrument")
data class Instrument(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        var id: Long = 0,

        @NotBlank
        @Size(max = MEDIUM_STRING_FIELD_LENGTH)
        @Column(name = "gps_coordinates")
        var gpsCoordinates: String,

        @NotBlank
        @Column(unique = true)
        var guid: String,

        @NotBlank
        var altitude: Float,

        @NotBlank
        var tilt: Float,

        @NotBlank
        var direction: Float,

        @NotBlank
        @Column(name = "calibration_value")
        var calibrationValue: Float,

        @Enumerated(EnumType.STRING)
        @Column(length = SHORT_STRING_FIELD_LENGTH)
        var state: InstrumentState,

        @NotBlank
        @ManyToOne
        @JoinColumn(name = "user_id")
        var user: User
) {
    @OneToMany(mappedBy = "instrument", cascade = [CascadeType.ALL], orphanRemoval = false)
    var instrumentMonitoredAreas: MutableSet<MonitoredArea> = mutableSetOf()

    @OneToMany(mappedBy = "instrument", cascade = [CascadeType.ALL], orphanRemoval = false, fetch = FetchType.LAZY) // TODO fetchTypeLazy have to work
    var instrumentMeasurements: MutableSet<InstrumentMeasurement> = mutableSetOf()

    fun addMonitoredArea(monitoredArea: MonitoredArea) {
        val instrumentMonitoredArea = MonitoredArea(
                id = monitoredArea.id,
                instrument = this,
                user = monitoredArea.user,
                inverter = monitoredArea.inverter,
                description = monitoredArea.description
        )
        instrumentMonitoredArea.monitoredAreaPvPanelAreas = monitoredArea.monitoredAreaPvPanelAreas
        instrumentMonitoredAreas.add(instrumentMonitoredArea)
    }

    fun removeMonitoredArea(monitoredArea: MonitoredArea): MonitoredArea {
        instrumentMonitoredAreas.remove(monitoredArea)
        return monitoredArea
    }

    fun addInstrumentMeasurement(m: InstrumentMeasurement) {
        val readingTypeInstrumentMeasurement = InstrumentMeasurement(
                instrument = this,
                readingType = m.readingType,
                readingValue = m.readingValue,
                measuredAt = m.measuredAt
        )
        instrumentMeasurements.add(readingTypeInstrumentMeasurement)

    }
}

enum class InstrumentState {
    CREATED,
    MEASURING,
    STOPPED,
    MALFUNCTIONING,
    DEPRECATED
}