package com.ffii.fpsms.modules.common.internalSetup

import com.ffii.core.utils.ExcelUtils
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.ss.usermodel.Workbook
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.springframework.stereotype.Component
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.transaction.annotation.Transactional
import com.ffii.fpsms.modules.user.entity.User
import com.ffii.fpsms.modules.user.entity.UserRepository
import java.io.File
import java.io.FileInputStream
import java.io.IOException

@Component
open class UserSetup {

    @Autowired
    private lateinit var userRepository: UserRepository

    @Autowired
    private lateinit var passwordEncoder: PasswordEncoder

    data class UserData(
        val staffNo: String,
        val name: String,
        val title: String,
        val authorityCodes: Set<String>
    )

    @Transactional(rollbackFor = [Exception::class])
    open fun importExcelFromLocal(filePath: String): Int {
        val file = File(filePath)
        if (!file.exists()) {
            throw IOException("File not found: $filePath")
        }

        FileInputStream(file).use { inputStream ->
            val workbook: Workbook = XSSFWorkbook(inputStream)

            try {
                val sheet: Sheet = workbook.getSheetAt(0)
                val userDataList = mutableListOf<UserData>()

                // ────────────────────────────────────────────────
                // Read header row (index 1) → map column index to authority code
                // ────────────────────────────────────────────────
                val headerRow = sheet.getRow(1) ?: throw IllegalStateException("Header row (index 1) not found")
                val columnToAuthority = mutableMapOf<Int, String>()

                for (col in 6..30) {  // adjust upper limit if more columns exist
                    val cell = headerRow.getCell(col)
                    if (cell != null) {
                        val headerValue = ExcelUtils.getStringValue(cell).trim()
                        if (headerValue.isNotEmpty()) {
                            val authCode = headerValue.uppercase()  // normalize to uppercase
                            columnToAuthority[col] = authCode
                        }
                    }
                }

                println("Detected ${columnToAuthority.size} authority columns from header row:")
                columnToAuthority.forEach { (col, code) ->
                    println("  Column $col → Authority code: '$code'")
                }
                println("")

                // ────────────────────────────────────────────────
                // Process data rows (starting from row index 2)
                // ────────────────────────────────────────────────
                for (rowIndex in 2..sheet.lastRowNum) {
                    val row = sheet.getRow(rowIndex) ?: continue

                    val staffNo = ExcelUtils.getStringValue(row.getCell(1)).trim()
                    if (staffNo.isEmpty()) continue

                    val name = ExcelUtils.getStringValue(row.getCell(2)).trim()
                    val title = ExcelUtils.getStringValue(row.getCell(3)).trim()

                    val authorityCodes = mutableSetOf<String>()

                    println("=== Processing row ${rowIndex + 1} (staffNo: $staffNo, name: $name) ===")

                    // Header-based columns
                    columnToAuthority.forEach { (colIndex, authCode) ->
                        val cell = row.getCell(colIndex)
                        val rawValue = if (cell == null) "" else ExcelUtils.getStringValue(cell)
                        val value = rawValue.trim()

                        println("  Col $colIndex | Raw: '${rawValue.take(40).replace("\n", "\\n")}' | Trimmed: '$value' | Len: ${value.length}")

                        val isNotBlank = value.isNotBlank()
                        println("     → non-blank? $isNotBlank")

                        if (isNotBlank) {
                            println("     → ADDING: $authCode")
                            authorityCodes.add(authCode)
                        } else {
                            println("     → skipped (empty/blank)")
                        }
                    }

                    println("  Final collected authorities: ${authorityCodes.joinToString(", ") { "'$it'" }}")
                    println("=== End of row ${rowIndex + 1} ===\n")

                    if (authorityCodes.isNotEmpty() || name.isNotEmpty() || title.isNotEmpty()) {
                        userDataList.add(UserData(staffNo, name, title, authorityCodes))
                    }
                }

                // ────────────────────────────────────────────────
                // Create users + assign authorities
                // ────────────────────────────────────────────────
                var createdCount = 0

                for (data in userDataList) {
                    val existing = userRepository.findByUsernameAndDeletedFalse(data.staffNo)
                    if (existing.isPresent) {
                        println("SKIP - User already exists: ${data.staffNo}")
                        continue
                    }

                    val user = User().apply {
                        username = data.staffNo
                        password = passwordEncoder.encode("Pings2026!")
                        locked = false
                        this.name = data.name
                        this.title = data.title
                        lotusNotesUser = false
                        staffNo = data.staffNo
                    }

                    val savedUser = userRepository.save(user)
                    createdCount++

                    println("CREATED user: ${data.staffNo} → ID = ${savedUser.id}")

                    data.authorityCodes.forEach { code ->
                        println("  → Assigning authority: '$code'")
                        userRepository.assignAuthorityByCodeIfNotExists(savedUser.id!!, code)
                    }

                    println("")
                }

                println("Import finished. Created $createdCount new users.")
                return createdCount

            } finally {
                workbook.close()
            }
        }
    }
}