package com.example.shiftalarm

import android.Manifest
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import androidx.activity.enableEdgeToEdge
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.shiftalarm.databinding.ActivityMainBinding
import java.time.LocalDate
import java.time.YearMonth
import java.time.format.DateTimeFormatter
import java.util.concurrent.TimeUnit
import androidx.recyclerview.widget.GridLayoutManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.util.Log
import kotlin.math.abs

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private val PREFS_NAME = "ShiftAlarmPrefs"
    private val KEY_TEAM = "selected_team"
    private var currentViewMonth: YearMonth = YearMonth.now(ShiftCalculator.SEOUL_ZONE)
    private var currentViewTeam: String = "A"
    private lateinit var gestureDetector: GestureDetector
    private var calendarAdapter: CalendarAdapter? = null
    private var isAnimatingMonth = false

    override fun onConfigurationChanged(newConfig: android.content.res.Configuration) {
        super.onConfigurationChanged(newConfig)
        // Smooth transition for theme change
        finish()
        startActivity(Intent(this, javaClass))
        overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        enableEdgeToEdge()
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            val density = resources.displayMetrics.density
            val p = (8 * density).toInt()
            v.setPadding(systemBars.left + p, systemBars.top + p, systemBars.right + p, systemBars.bottom + p)
            insets
        }

        setupCalendar()
        setupWorker()
        setupSwipeGesture()
        AppUpdateManager.checkUpdate(this, silent = true)

        val prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
        currentViewTeam = prefs.getString(KEY_TEAM, "A") ?: "A"
        
        // Default to Shift Calendar mode (checkbox unchecked)
        binding.cbShowHolidays.isChecked = false

        binding.btnSettings.setOnClickListener {
            startActivity(Intent(this, SettingsActivity::class.java))
        }

        binding.prevMonth.setOnClickListener {
            animateMonthTransition(-1)
        }

        binding.monthTitle.setOnClickListener {
            showMonthYearPicker()
        }

        binding.nextMonth.setOnClickListener {
            animateMonthTransition(1)
        }
        
        binding.btnToday.setOnClickListener {
            val prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
            currentViewTeam = prefs.getString(KEY_TEAM, "A") ?: "A"
            currentViewMonth = YearMonth.now(ShiftCalculator.SEOUL_ZONE)
            updateCalendar()
        }

        binding.cbShowHolidays.setOnCheckedChangeListener { _, _ ->
            updateCalendar()
        }

        binding.alarmInfoBar.setOnClickListener {
            val intent = Intent(this, SettingsActivity::class.java)
            intent.putExtra("TARGET_TAB", 1) // 1 is Alarm tab
            startActivity(intent)
        }

        // Tide Location Cycle Logic
        val tideLocations = listOf("군산", "변산", "여수", "태안")
        binding.btnTideLocation.setOnClickListener {
            val currentLoc = prefs.getString("selected_tide_location", "군산") ?: "군산"
            val nextIndex = (tideLocations.indexOf(currentLoc) + 1) % tideLocations.size
            val nextLoc = tideLocations[nextIndex]
            
            prefs.edit().putString("selected_tide_location", nextLoc).apply()
            binding.btnTideLocation.text = nextLoc
            updateCalendar()
        }

        // setupWorker(), checkRoot() 등은 이미 호출됨
    }

    private fun updateTideButtonVisibility() {
        val prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
        val showTide = prefs.getBoolean("show_tide", false)
        val currentLoc = prefs.getString("selected_tide_location", "군산") ?: "군산"
        
        if (showTide) {
            binding.btnTideLocation.visibility = android.view.View.VISIBLE
            binding.btnTideLocation.text = currentLoc
        } else {
            binding.btnTideLocation.visibility = android.view.View.GONE
        }
    }

    private fun setupSwipeGesture() {
        gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
            private val SWIPE_THRESHOLD = 100
            private val SWIPE_VELOCITY_THRESHOLD = 100

            override fun onDown(e: MotionEvent): Boolean {
                return true
            }

            override fun onFling(
                e1: MotionEvent?,
                e2: MotionEvent,
                velocityX: Float,
                velocityY: Float
            ): Boolean {
                if (e1 == null) return false
                
                val diffX = e2.x - e1.x
                val diffY = e2.y - e1.y
                
                if (abs(diffX) > abs(diffY)) {
                    if (abs(diffX) > SWIPE_THRESHOLD && abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            // Swipe Right -> Previous Month
                            animateMonthTransition(-1)
                        } else {
                            // Swipe Left -> Next Month
                            animateMonthTransition(1)
                        }
                        return true
                    }
                }
                return false
            }
        })

        binding.calendarGrid.addOnItemTouchListener(object : androidx.recyclerview.widget.RecyclerView.OnItemTouchListener {
            override fun onInterceptTouchEvent(rv: androidx.recyclerview.widget.RecyclerView, e: MotionEvent): Boolean {
                gestureDetector.onTouchEvent(e)
                return false
            }
            override fun onTouchEvent(rv: androidx.recyclerview.widget.RecyclerView, e: MotionEvent) {}
            override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
        })

        binding.calendarContainer.setOnTouchListener { _, event ->
            gestureDetector.onTouchEvent(event)
            true
        }
    }

    override fun onResume() {
        super.onResume()
        val prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
        currentViewTeam = prefs.getString(KEY_TEAM, "A") ?: "A"

        updateTideButtonVisibility()
        updateCalendar()

        // 일원화된 통합 권한 체크 실행 (신뢰도 100% 보장)
        AlarmPermissionUtil.checkAndRequestAllPermissions(this)

        // 설정 변경 시 즉시 반영을 위한 강제 동기화 (30일 스케줄링)
        lifecycleScope.launch {
            syncAllAlarms(this@MainActivity)
        }

        // 연차 정보 업데이트
        lifecycleScope.launch {
            val repo = ShiftRepository(this@MainActivity)
            val annualLeave = repo.getAnnualLeave()
            annualLeave?.let {
                binding.tvAnnualLeave.text = "연차: ${formatRemainingDays(it.remainingDays)}"
            } ?: run {
                binding.tvAnnualLeave.text = "연차: --"
            }
        }
    }

    private fun showMonthYearPicker() {
        val dialogView = layoutInflater.inflate(R.layout.dialog_month_year_picker, null)
        val yearPicker = dialogView.findViewById<android.widget.NumberPicker>(R.id.yearPicker)
        val monthPicker = dialogView.findViewById<android.widget.NumberPicker>(R.id.monthPicker)

        val currentYear = currentViewMonth.year
        val currentMonth = currentViewMonth.monthValue

        yearPicker.minValue = 2010
        yearPicker.maxValue = 2050
        yearPicker.value = currentYear
        yearPicker.wrapSelectorWheel = false

        monthPicker.minValue = 1
        monthPicker.maxValue = 12
        monthPicker.value = currentMonth
        monthPicker.displayedValues = arrayOf("1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월")

        val dialog = androidx.appcompat.app.AlertDialog.Builder(this, R.style.OneUI8_Dialog)
            .setView(dialogView)
            .create()

        // Internal button click handlers
        dialogView.findViewById<android.widget.Button>(R.id.btnCancel).setOnClickListener {
            dialog.dismiss()
        }
        dialogView.findViewById<android.widget.Button>(R.id.btnConfirm).setOnClickListener {
            currentViewMonth = YearMonth.of(yearPicker.value, monthPicker.value)
            updateCalendar()
            dialog.dismiss()
        }

        dialog.show()
        
        // 90% Screen Width for One UI 8.0 feel
        val width = (resources.displayMetrics.widthPixels * 0.9).toInt()
        dialog.window?.setLayout(width, android.view.ViewGroup.LayoutParams.WRAP_CONTENT)
        dialog.window?.setDimAmount(0.6f)
    }

    private fun dpToPx(dp: Float): Int {
        return (dp * resources.displayMetrics.density).toInt()
    }

    private fun setupCalendar() {
        binding.calendarGrid.layoutManager = GridLayoutManager(this, 7)
        binding.calendarGrid.itemAnimator = null
        updateCalendar()
    }

    private suspend fun loadCalendarDataForMonth(targetMonth: YearMonth) {
        val prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
        val selectedTeam = prefs.getString(KEY_TEAM, "A") ?: "A"
        val factory = prefs.getString("selected_factory", "Jeonju") ?: "Jeonju"
        val today = LocalDate.now(ShiftCalculator.SEOUL_ZONE)
        
        val db = AppDatabase.getDatabase(this@MainActivity)
        val dao = db.shiftDao()
        val repo = ShiftRepository(this@MainActivity)
        
        // 전체 사용자 알람 로드 (일원화된 Room DB 사용)
        val allCustomAlarms = repo.getAllCustomAlarms()

        // 디스플레이 업데이트
        if (currentViewTeam == selectedTeam) {
            val shiftForMyTeam = withContext(Dispatchers.IO) { repo.getShift(today, selectedTeam, factory) }
            updateAlarmTimeDisplay(today, shiftForMyTeam, factory, allCustomAlarms)
            binding.alarmTimeText.visibility = android.view.View.VISIBLE
        } else {
            binding.alarmTimeText.visibility = android.view.View.GONE
        }

        // Load overrides and memos for the month
        val monthStr = targetMonth.toString()
        val overrides = withContext(Dispatchers.IO) { 
            dao.getOverridesForMonth(factory, currentViewTeam, monthStr).associateBy { overrideItem -> overrideItem.date }
        }
        val memos = withContext(Dispatchers.IO) { 
            dao.getMemosForMonth(monthStr).associateBy { memoItem -> memoItem.date }
        }

        val days = generateDaysForMonthWithData(targetMonth, currentViewTeam, factory, overrides, memos)

        val availableHeight = binding.calendarGrid.height
        val calcRowHeight = if (availableHeight > 0) availableHeight / 5 else 0

        if (calendarAdapter == null || binding.calendarGrid.adapter == null) {
            val newAdapter = CalendarAdapter(days, object : CalendarAdapter.OnDayClickListener {
                override fun onDayClick(date: LocalDate, currentShift: String) {
                    showDaySettingsDialog(date, currentShift)
                }
            }, binding.cbShowHolidays.isChecked)
            if (calcRowHeight > 0) {
                newAdapter.rowHeight = calcRowHeight
            }
            calendarAdapter = newAdapter
            binding.calendarGrid.adapter = newAdapter
        } else {
            calendarAdapter?.let { ad ->
                ad.days = days
                ad.showHolidays = binding.cbShowHolidays.isChecked
                if (calcRowHeight > 0) {
                    ad.rowHeight = calcRowHeight
                }
                ad.notifyDataSetChanged()
            }
        }

        binding.monthTitle.text = targetMonth.format(DateTimeFormatter.ofPattern("yyyy년 MM월"))

        if (calcRowHeight == 0) {
            binding.calendarGrid.post {
                val h = binding.calendarGrid.height
                if (h > 0) {
                    val rH = h / 5
                    calendarAdapter?.let {
                        if (it.rowHeight != rH) {
                            it.rowHeight = rH
                            it.notifyDataSetChanged()
                        }
                    }
                }
            }
        }

        // Update Header Status Text with Permission Warning if needed
        val shiftForViewingTeam = withContext(Dispatchers.IO) { repo.getShift(today, currentViewTeam, factory) }
        val teamSuffix = if (currentViewTeam == selectedTeam) " (내 반)" else " (${currentViewTeam}반)"
        
        if (currentViewTeam == selectedTeam && !AlarmPermissionUtil.getExactAlarmStatus(this@MainActivity)) {
            binding.todayStatusText.text = "⚠️ 정확한 알람 권한이 필요합니다 (설정 필요)"
            binding.todayStatusText.setTextColor(androidx.core.content.ContextCompat.getColor(this@MainActivity, R.color.warning_red))
        } else {
            binding.todayStatusText.text = "오늘의 근무: $shiftForViewingTeam$teamSuffix"
            binding.todayStatusText.setTextColor(androidx.core.content.ContextCompat.getColor(this@MainActivity, R.color.text_secondary))
        }

        // Update Annual Leave display
        val annualLeave = withContext(Dispatchers.IO) { repo.getAnnualLeave() }
        annualLeave?.let {
            binding.tvAnnualLeave.text = "연차: ${formatRemainingDays(it.remainingDays)}"
        } ?: run {
            binding.tvAnnualLeave.text = "연차: --"
        }

        // Update Shift Summary Chips (v2.2.0)
        val juCount = days.count { it.date != null && (it.shift == "주간" || it.shift == "주") }
        val seokCount = days.count { it.date != null && (it.shift == "석간" || it.shift == "석") }
        val yaCount = days.count { it.date != null && (it.shift == "야간" || it.shift == "야") }
        val monthlyOvertime = withContext(Dispatchers.IO) { repo.getMonthlyOvertimeHours(targetMonth) }

        binding.chipJu.text = "주간 ${juCount}일"
        binding.chipSeok.text = "석간 ${seokCount}일"
        binding.chipYa.text = "야간 ${yaCount}일"
        binding.chipOvertime.text = "연장 ${monthlyOvertime}h"

        updateOtherTeamsLayout(today, factory, prefs)
    }

    private fun updateCalendar() {
        lifecycleScope.launch {
            loadCalendarDataForMonth(currentViewMonth)
        }
    }

    private fun updateOtherTeamsLayout(today: LocalDate, factory: String, prefs: android.content.SharedPreferences) {
        val teamColors = mapOf(
            "A" to R.color.team_a_color,
            "B" to R.color.team_b_color,
            "C" to R.color.team_c_color,
            "D" to R.color.team_d_color
        )
        val container = binding.otherTeamsContainer
        container.removeAllViews()

        val rowLayout = android.widget.LinearLayout(this).apply {
            orientation = android.widget.LinearLayout.HORIZONTAL
            layoutParams = android.widget.LinearLayout.LayoutParams(
                android.widget.LinearLayout.LayoutParams.MATCH_PARENT,
                android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
            )
        }
        
        val allTeams = if (factory == "Nonsan") listOf("A", "B", "C") else listOf("A", "B", "C", "D")

        lifecycleScope.launch {
            for (t in allTeams) {
                val shift = ShiftCalculator.getShift(today, t, factory)
                val shortShift = when(shift) {
                    "주간" -> "주"
                    "석간" -> "석"
                    "야간" -> "야"
                    "주간 맞교대" -> "주맞"
                    "야간 맞교대" -> "야맞"
                    "휴무", "휴가" -> "휴"
                    else -> shift.take(1)
                }

                val textView = android.widget.TextView(this@MainActivity).apply {
                    text = "${t}반 ($shortShift)"
                    setPadding(0, 24, 0, 24) 
                    textSize = 12f 
                    gravity = android.view.Gravity.CENTER
                    setTypeface(null, android.graphics.Typeface.BOLD)
                    
                    if (currentViewTeam == t) {
                        setTextColor(android.graphics.Color.WHITE)
                        setBackgroundResource(R.drawable.bg_pill_rect_selected)
                    } else {
                        setTextColor(androidx.core.content.ContextCompat.getColor(context, teamColors[t]!!))
                        setBackgroundResource(R.drawable.bg_pill_rect_unselected)
                    }
                    
                    layoutParams = android.widget.LinearLayout.LayoutParams(0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 1f).apply {
                        setMargins(4, 0, 4, 0)
                    }
                    
 setOnClickListener {
 if (currentViewTeam != t) {
 currentViewTeam = t
 updateCalendar()
 showCustomToast(context, "${t}반 근무표를 표시합니다.")
 }
 }
                }
                rowLayout.addView(textView)
            }
            container.addView(rowLayout)
        }
    }

    private fun generateDaysForMonthWithData(
        month: YearMonth,
        team: String,
        factory: String,
        overrides: Map<String, ShiftOverride>,
        memos: Map<String, DailyMemo>
    ): List<DayShift> {
        val daysInMonth = month.lengthOfMonth()
        val firstDayOfMonth = month.atDay(1).dayOfWeek.value % 7 
        val actualDayCount = firstDayOfMonth + daysInMonth
        val targetCells = if (actualDayCount <= 35) 35 else 42
        
        val dayList = mutableListOf<DayShift>()
        
        for (i in 0 until firstDayOfMonth) {
            dayList.add(DayShift(null, null))
        }

        for (day in 1..daysInMonth) {
            val date = month.atDay(day)
            val dateStr = date.toString()
            
            val shift = overrides[dateStr]?.shift ?: ShiftCalculator.getShift(date, team, factory)
            val memo = memos[dateStr]
            val hasMemo = memo != null
            val memoContent = memo?.content
            
            dayList.add(DayShift(date, shift, hasMemo, memoContent))
        }

        while (dayList.size < targetCells) {
            dayList.add(DayShift(null, null))
        }
        return dayList
    }
    
    private fun getAlarmsStrForDate(date: LocalDate, shift: String, allAlarms: List<CustomAlarm>): List<String> {
        val alarmTimes = mutableListOf<String>()
        val isOff = shift == "휴무" || shift == "휴가"
        
        for (alarm in allAlarms) {
            if (alarm.isEnabled && (alarm.shiftType == "기타" || (!isOff && alarm.shiftType == shift))) {
                if (!alarmTimes.contains(alarm.time)) {
                    alarmTimes.add(alarm.time)
                }
            }
        }
        
        alarmTimes.sort()
        return alarmTimes
    }

    private fun updateAlarmTimeDisplay(date: LocalDate, shift: String, factory: String, allAlarms: List<CustomAlarm>) {
        val prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
        // 0. Check Master Switch
        if (!ShiftAlarmDefaults.isMasterAlarmEnabled(prefs)) {
            binding.alarmTimeText.text = "전체 알람 꺼짐"
            binding.alarmTimeText.visibility = android.view.View.VISIBLE
            binding.alarmTimeText.setTextColor(androidx.core.content.ContextCompat.getColor(this, R.color.shift_red))
            binding.alarmTimeText.setTypeface(null, android.graphics.Typeface.BOLD)
            return
        }

        val todayStr = getAlarmsStrForDate(date, shift, allAlarms).firstOrNull() ?: "없음"
        val tomorrowDate = date.plusDays(1)
        val repo = ShiftRepository(this)
        
        lifecycleScope.launch(Dispatchers.IO) {
            val tomorrowShiftFull = repo.getShift(tomorrowDate, currentViewTeam, factory)
            val tomorrowAlarms = getAlarmsStrForDate(tomorrowDate, tomorrowShiftFull, allAlarms)
            val tomorrowStr = tomorrowAlarms.firstOrNull() ?: "없음"
            
            withContext(Dispatchers.Main) {
                if (!ShiftAlarmDefaults.isMasterAlarmEnabled(prefs)) {
                     binding.alarmTimeText.text = "전체 알람 꺼짐"
                     binding.alarmTimeText.setTextColor(androidx.core.content.ContextCompat.getColor(this@MainActivity, R.color.shift_red))
                     return@withContext
                }

                val todayLabel = "오늘: $todayStr"
                val tomorrowLabel = "내일: $tomorrowStr"
                
                binding.alarmTimeText.text = "$todayLabel  |  $tomorrowLabel"
                binding.alarmTimeText.visibility = android.view.View.VISIBLE
                binding.alarmTimeText.setTypeface(null, android.graphics.Typeface.BOLD)
                binding.alarmTimeText.setTextColor(androidx.core.content.ContextCompat.getColor(this@MainActivity, R.color.text_primary))
            }
        }
    }

    private fun showDaySettingsDialog(date: LocalDate, currentShift: String) {
        val dialogView = layoutInflater.inflate(R.layout.dialog_day_settings, null)
        val dialog = androidx.appcompat.app.AlertDialog.Builder(this)
            .setView(dialogView)
            .create()
        dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)

        val prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
        val factory = prefs.getString("selected_factory", "Jeonju") ?: "Jeonju"
        val team = prefs.getString(KEY_TEAM, "A") ?: "A"

        // Set Title - One UI Style Header
        val titleText = dialogView.findViewById<android.widget.TextView>(R.id.dialogTitle)
        val subtitleText = dialogView.findViewById<android.widget.TextView>(R.id.dialogSubtitle)
        
        subtitleText.text = if (date == LocalDate.now()) "오늘의 근무" else "${date.monthValue}월 ${date.dayOfMonth}일 근무"
        titleText.text = "$currentShift"

        // Button Handlers
        val actionMap = mapOf(
            R.id.btnJu to "주간",
            R.id.btnJuMat to "주간 맞교대",
            R.id.btnSeok to "석간",
            R.id.btnYa to "야간",
            R.id.btnYaMat to "야간 맞교대",
            R.id.btnOff to "휴무",
            R.id.btnWolcha to "월차",
            R.id.btnYeoncha to "연차",
            R.id.btnBanwol to "반월",
            R.id.btnBannyeon to "반년",
            R.id.btnEdu to "교육",
            R.id.btnManual to "직접 입력",
            R.id.btnReset to "원래대로"
        )
        
        fun applyStrokeStyle(viewId: Int, shiftType: String) {
             val view = dialogView.findViewById<android.widget.TextView>(viewId)
             val colorRes = when(shiftType) {
                 "주간" -> R.color.shift_ju
                 "석간" -> R.color.shift_seok
                 "야간" -> R.color.shift_ya
                 "주간 맞교대" -> R.color.shift_jumat
                 "야간 맞교대" -> R.color.shift_yamat
                 "휴무", "휴가" -> R.color.shift_off
                 "월차", "연차" -> R.color.secondary
                 "반월", "반년" -> R.color.shift_red
                 "교육" -> R.color.primary
                 "원래대로" -> R.color.text_secondary
                 else -> R.color.shift_gray
             }
             val color = androidx.core.content.ContextCompat.getColor(this, colorRes)
             
             view.setTextColor(color)
             
             // Create Stroke Drawable Programmatically
             val drawable = android.graphics.drawable.GradientDrawable()
             drawable.shape = android.graphics.drawable.GradientDrawable.OVAL
             drawable.setColor(android.graphics.Color.TRANSPARENT)
             val density = resources.displayMetrics.density
             drawable.setStroke((1.5 * density).toInt(), color)
             
             view.background = drawable
        }

        actionMap.forEach { (id, type) -> applyStrokeStyle(id, type) }

        // Memo Handling
        val etMemo = dialogView.findViewById<android.widget.EditText>(R.id.etMemo)
        val repo = ShiftRepository(this)
        lifecycleScope.launch {
            val existingMemo = repo.getMemo(date)
            etMemo.setText(existingMemo ?: "")
        }

        for ((id, action) in actionMap) {
            dialogView.findViewById<android.view.View>(id).setOnClickListener {
                lifecycleScope.launch {
                    val content = etMemo.text.toString().trim()
                    repo.setMemo(date, content) // Save memo even when shift button clicked
                    handleDaySettingAction(date, action, team, factory)
                    dialog.dismiss()
                }
            }
        }

        dialogView.findViewById<android.view.View>(R.id.btnClearMemo).setOnClickListener {
            etMemo.setText("")
            lifecycleScope.launch {
                repo.setMemo(date, "")
                updateCalendar()
                Toast.makeText(this@MainActivity, "메모가 삭제되었습니다.", Toast.LENGTH_SHORT).show()
            }
        }

        dialogView.findViewById<android.view.View>(R.id.btnClose).setOnClickListener {
            lifecycleScope.launch {
                val content = etMemo.text.toString().trim()
                repo.setMemo(date, content)
                updateCalendar()
                dialog.dismiss()
            }
        }

        dialog.show()
    }
    
    private suspend fun handleDaySettingAction(date: LocalDate, selected: String, team: String, factory: String) {
        val repo = ShiftRepository(this)
        val prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)


        when (selected) {
            "원래대로" -> {
                repo.clearOverride(date, team, factory)
                repo.setMemo(date, "") // Clear memo too on reset
                android.widget.Toast.makeText(this, "원래 근무로 복구되었습니다.", android.widget.Toast.LENGTH_SHORT).show()
                syncAllAlarms(this)
                updateCalendar()
                repo.updateRemainingAnnualLeave()
            }
            "직접 입력" -> {
                showCustomInputDialog(date, repo, team, factory)
            }
            "주간", "석간", "야간", "주간 맞교대", "야간 맞교대" -> {
                // Standard Shifts -> Override Shift WITHOUT manual time
                repo.setOverride(date, selected, team, factory)
                updateCalendar()
                // Alarms are handled by syncAllAlarms/CustomAlarms during updateCalendar
                syncAllAlarms(this)
                android.widget.Toast.makeText(this, "${date} [$selected]로 설정되었습니다.", android.widget.Toast.LENGTH_SHORT).show()
            }
            "휴무" -> {
                // Standard Off
                repo.setOverride(date, selected, team, factory)
                updateCalendar()
                syncAllAlarms(this)
                android.widget.Toast.makeText(this, "${selected}로 설정되었습니다. 알람이 해제됩니다.", android.widget.Toast.LENGTH_SHORT).show()
            }
            else -> {
                // New Types: 월차, 연차, 반월, 반년, 교육 -> Saved as Override with no time
                repo.setOverride(date, selected, team, factory)
                // 연차 계산을 먼저 수행하고 달력 업데이트
                repo.updateRemainingAnnualLeave()
                updateCalendar()
                syncAllAlarms(this)
                android.widget.Toast.makeText(this, "${selected}(으)로 기록되었습니다. 알람이 해제됩니다.", android.widget.Toast.LENGTH_SHORT).show()
            }
        }
    }
    
    private fun showCustomInputDialog(date: LocalDate, repo: ShiftRepository, team: String, factory: String) {
        val layout = android.widget.LinearLayout(this).apply {
            orientation = android.widget.LinearLayout.VERTICAL
            setPadding(50, 40, 50, 10)
        }

        val etMemoInput = android.widget.EditText(this).apply {
            hint = "메모 내용 (예: 회식, 교육, 출장)"
            maxLines = 1
            filters = arrayOf(android.text.InputFilter.LengthFilter(20))
        }
        
        layout.addView(etMemoInput)
        
        androidx.appcompat.app.AlertDialog.Builder(this)
            .setTitle("${date.monthValue}월 ${date.dayOfMonth}일 메모 입력")
            .setView(layout)
            .setPositiveButton("확인") { _, _ ->
                val content = etMemoInput.text.toString().trim()
                
                if (content.isNotEmpty()) {
                    lifecycleScope.launch {
                        // Direct Input -> Set as Memo. 
                        // We do NOT change the shift (keep default or existing override).
                        // If user wants to change shift, they should use the specific buttons.
                        repo.setMemo(date, content)
                        updateCalendar()
                        android.widget.Toast.makeText(this@MainActivity, "메모가 저장되었습니다.", android.widget.Toast.LENGTH_SHORT).show()
                    }
                } else {
                    android.widget.Toast.makeText(this, "입력이 취소되었습니다.", android.widget.Toast.LENGTH_SHORT).show()
                }
            }
            .setNegativeButton("취소", null)
            .show()
    }
    

    private fun setupWorker() {
        val workRequest = PeriodicWorkRequestBuilder<AlarmWorker>(24, TimeUnit.HOURS)
            .setInitialDelay(calculateDelayToMidnight(), TimeUnit.MILLISECONDS)
            .build()

        WorkManager.getInstance(this).enqueueUniquePeriodicWork(
            "DailyShiftCheck",
            ExistingPeriodicWorkPolicy.KEEP,
            workRequest
        )
    }

    private fun calculateDelayToMidnight(): Long {
        val seoulZone = java.time.ZoneId.of("Asia/Seoul")
        val now = java.time.LocalDateTime.now(seoulZone)
        val midnight = now.plusDays(1).withHour(0).withMinute(0).withSecond(1)
        return java.time.Duration.between(now, midnight).toMillis()
    }

    private fun animateMonthTransition(direction: Int) {
        if (isAnimatingMonth) return
        val card = binding.calendarCard
        val snapshot = binding.calendarOverlaySnapshot
        val width = card.width.toFloat()

        val nextMonth = if (direction > 0) {
            currentViewMonth.plusMonths(1)
        } else {
            currentViewMonth.minusMonths(1)
        }

        if (width == 0f) {
            currentViewMonth = nextMonth
            updateCalendar()
            return
        }

        isAnimatingMonth = true

        // 1. Capture bitmap snapshot of current calendar card
        try {
            val bitmap = Bitmap.createBitmap(card.width, card.height, Bitmap.Config.ARGB_8888)
            val canvas = Canvas(bitmap)
            card.draw(canvas)
            snapshot.setImageBitmap(bitmap)
            snapshot.visibility = android.view.View.VISIBLE
            snapshot.alpha = 1.0f
            snapshot.scaleX = 1.0f
            snapshot.scaleY = 1.0f
            snapshot.translationX = 0f
        } catch (e: Exception) {
            Log.w("MainActivity", "Failed to capture snapshot for month transition", e)
        }

        // 2. Position top card offscreen before loading
        card.translationX = if (direction > 0) width else -width
        currentViewMonth = nextMonth

        // 3. Load next month's data BEFORE starting slide animation to eliminate any flicker
        lifecycleScope.launch {
            loadCalendarDataForMonth(currentViewMonth)

            val fluidInterpolator = androidx.core.view.animation.PathInterpolatorCompat.create(0.22f, 1.0f, 0.36f, 1.0f)
            val duration = 280L

            card.animate()
                .translationX(0f)
                .setDuration(duration)
                .setInterpolator(fluidInterpolator)
                .withEndAction {
                    snapshot.visibility = android.view.View.GONE
                    snapshot.setImageDrawable(null)
                    isAnimatingMonth = false
                }
                .start()

            snapshot.animate()
                .scaleX(0.94f)
                .scaleY(0.94f)
                .alpha(0.35f)
                .translationX(if (direction > 0) -width * 0.22f else width * 0.22f)
                .setDuration(duration)
                .setInterpolator(fluidInterpolator)
                .start()
        }
    }

    private fun formatRemainingDays(days: Float): String {
        return if (days == days.toInt().toFloat()) {
            // 정수인 경우
            days.toInt().toString()
        } else {
            // 소숫점이 있는 경우 (0.5 등)
            String.format("%.1f", days)
        }
    }
}
