package com.ffii.fpsms.modules.master.service

import com.ffii.core.support.AbstractBaseEntityService
import com.ffii.core.support.JdbcDao
import com.ffii.fpsms.modules.master.entity.EquipmentDetail
import com.ffii.fpsms.modules.master.entity.EquipmentDetailRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import com.ffii.fpsms.modules.master.web.models.NewEquipmentDetailRequest
import com.ffii.fpsms.modules.master.web.models.UpdateMaintenanceRequest
import java.time.LocalDateTime

@Service
open class EquipmentDetailService(
    private val jdbcDao: JdbcDao,
    private val equipmentDetailRepository: EquipmentDetailRepository,
) : AbstractBaseEntityService<EquipmentDetail, Long, EquipmentDetailRepository>(jdbcDao, equipmentDetailRepository) {

    open fun allEquipmentDetails(): List<EquipmentDetail> {
        return equipmentDetailRepository.findAll()
    }

    open fun getEquipmentDetailsByPage(args: Map<String, Any>): List<Map<String, Any>> {
        println("Search args: $args")
        
        val sql = StringBuilder(
            """
            SELECT 
                e.id AS id,
                e.code AS code,
                e.name AS name,
                e.description AS description,
                e.equipmentCode AS equipmentCode,
                e.repairAndMaintenanceStatus AS repairAndMaintenanceStatus,
                e.latestRepairAndMaintenanceDate AS latestRepairAndMaintenanceDate,
                e.lastRepairAndMaintenanceDate AS lastRepairAndMaintenanceDate,
                e.repairAndMaintenanceRemarks AS repairAndMaintenanceRemarks
            FROM equipment_detail e 
            LEFT JOIN equipment eq ON e.equipmentTypeId = eq.id
            """
        )

        val whereConditions = mutableListOf<String>()
        
        whereConditions.add("e.deleted = FALSE")
        whereConditions.add("eq.deleted = FALSE")
    
        val searchTerm = args["equipmentCode"] as? String
        val codeTerm = args["code"] as? String
        
        if (searchTerm != null && codeTerm != null && searchTerm == codeTerm) {

            whereConditions.add("(LOWER(e.code) LIKE LOWER(:equipmentCode) OR LOWER(e.equipmentCode) LIKE LOWER(:equipmentCode))")
        } else {

            if (codeTerm != null && (searchTerm == null || searchTerm != codeTerm)) {
                whereConditions.add("LOWER(e.code) LIKE LOWER(:code)")
            }
            if (searchTerm != null && (codeTerm == null || searchTerm != codeTerm)) {
                whereConditions.add("LOWER(e.equipmentCode) LIKE LOWER(:equipmentCode)")
            }
        }
        
        if (args.containsKey("id")) {
            whereConditions.add("e.id like :id")
        }
        if (args.containsKey("name")) {
            whereConditions.add("LOWER(e.name) LIKE LOWER(:name)")
        }
        if (args.containsKey("description")) {

            whereConditions.add("e.description = :description")
        }
        if (args.containsKey("repairAndMaintenanceStatus")) {
            whereConditions.add("e.repairAndMaintenanceStatus = :repairAndMaintenanceStatus")
        }
        
        if (whereConditions.isNotEmpty()) {
            sql.append("WHERE ${whereConditions.joinToString(" AND ")}")
        }
        return jdbcDao.queryForList(sql.toString(), args)
    }

    open fun getEquipmentDetailsByEquipmentId(equipmentId: Long): List<Map<String, Any>> {
        val sql = """
            SELECT 
                ed.id AS id,
                ed.code AS code,
                ed.name AS name,
                ed.description AS description,
                ed.equipmentCode AS equipmentCode,
                ed.repairAndMaintenanceStatus AS repairAndMaintenanceStatus,
                ed.latestRepairAndMaintenanceDate AS latestRepairAndMaintenanceDate,
                ed.lastRepairAndMaintenanceDate AS lastRepairAndMaintenanceDate,
                ed.repairAndMaintenanceRemarks AS repairAndMaintenanceRemarks
            FROM equipment_detail ed
            LEFT JOIN equipment e ON ed.equipmentTypeId = e.id
            WHERE ed.deleted = FALSE
            AND e.id = :equipmentId
            AND e.deleted = FALSE
        """
        
        val args = mapOf("equipmentId" to equipmentId)
        return jdbcDao.queryForList(sql, args)
    }

    open fun getEquipmentDetailsByDescriptionIncludingDeleted(description: String): List<Map<String, Any>> {
        val sql = """
            SELECT 
                e.id AS id,
                e.code AS code,
                e.name AS name,
                e.description AS description,
                e.equipmentCode AS equipmentCode,
                e.repairAndMaintenanceStatus AS repairAndMaintenanceStatus,
                e.latestRepairAndMaintenanceDate AS latestRepairAndMaintenanceDate,
                e.lastRepairAndMaintenanceDate AS lastRepairAndMaintenanceDate,
                e.repairAndMaintenanceRemarks AS repairAndMaintenanceRemarks
            FROM equipment_detail e 
            WHERE e.description = :description
        """
        
        val args = mapOf("description" to description)
        return jdbcDao.queryForList(sql, args)
    }

    open fun findById(id: Long): EquipmentDetail? {
        return equipmentDetailRepository.findByIdAndDeletedFalse(id)
    }
/*
    open fun findByCode(code: String): EquipmentDetail? {
        return equipmentDetailRepository.findByCodeAndDeletedIsFalse(code)
    }
*/
    open fun findByName(name: String): EquipmentDetail? {
        return equipmentDetailRepository.findByNameAndDeletedIsFalse(name)
    }

    open fun findByDescription(description: String): EquipmentDetail? {
        return equipmentDetailRepository.findByDescriptionAndDeletedIsFalse(description)
    }

    @Transactional
    open fun updateMaintenanceAndRepair(
        id: Long,
        request: UpdateMaintenanceRequest
    ): EquipmentDetail {
        val equipmentDetail = findById(id)
            ?: throw IllegalArgumentException("Equipment detail not found with id: $id")
        
        val previousStatus = equipmentDetail.repairAndMaintenanceStatus
        val previousLatestDate = equipmentDetail.latestRepairAndMaintenanceDate
        
        equipmentDetail.repairAndMaintenanceStatus = request.repairAndMaintenanceStatus
        equipmentDetail.repairAndMaintenanceRemarks = request.repairAndMaintenanceRemarks
        
        when {
            previousStatus == true && request.repairAndMaintenanceStatus == false -> {
                equipmentDetail.lastRepairAndMaintenanceDate = previousLatestDate
                equipmentDetail.latestRepairAndMaintenanceDate = LocalDateTime.now()
            }
            previousStatus == false && request.repairAndMaintenanceStatus == true -> {
            }
        }
        
        return equipmentDetailRepository.saveAndFlush(equipmentDetail)
    }
    @Transactional
    open fun saveEquipmentDetail(request: NewEquipmentDetailRequest): EquipmentDetail {

        if (request.code.isNullOrBlank()) {
            throw IllegalArgumentException("Equipment detail code cannot be null or blank")
        }
        
        if (request.id != null && request.id > 0) {
            val duplicated = equipmentDetailRepository.findByCodeAndDeletedIsFalse(request.code!!)
            if (duplicated != null && duplicated.id != request.id) {
                throw IllegalArgumentException("Equipment detail code already exists")
            }
        }

        val entity = if (request.id != null && request.id > 0) {
            equipmentDetailRepository.findByIdAndDeletedFalse(request.id) ?: EquipmentDetail()
        } else {
            EquipmentDetail()
        }

        entity.code = request.code
        entity.name = request.name
        entity.description = request.description
        entity.equipmentTypeId = request.equipmentTypeId
        entity.equipmentCode = request.equipmentCode
        entity.repairAndMaintenanceStatus = request.repairAndMaintenanceStatus ?: false

        return equipmentDetailRepository.saveAndFlush(entity)
    }
    @Transactional
    open fun deleteEquipmentDetail(id: Long) {
        val equipmentDetail = equipmentDetailRepository.findByIdAndDeletedFalse(id)
        equipmentDetail?.let { et ->
            et.deleted = true
            equipmentDetailRepository.saveAndFlush(et)
        }
    }
}