Attribute VB_Name = "Common_Button"
Option Explicit

' --- Private Variables ---
Private m_LastErrorMsg As String

' ============================================================
' Get/Set last error message
' ============================================================
Public Sub SetLastErrorMsg(msg As String)
    m_LastErrorMsg = msg
End Sub

Public Function GetLastErrorMsg() As String
    GetLastErrorMsg = m_LastErrorMsg
End Function

Public Sub ClearLastErrorMsg()
    m_LastErrorMsg = ""
End Sub

' ============================================================
' Module Name: Common_Button
' Module Desc: Common button handlers with centralized error handling
' Public Methods:
'   - CSV_Import_Button    (CSV import entry, binds to sheet button)
'   - Validation_Button    (validation entry, binds to sheet button)
'   - CSV_Export_Button    (CSV export entry, binds to sheet button)
'   - Sort_Button          (sort entry, binds to sheet button)
'   - Filter_Button       (filter entry, binds to sheet button)
'   - Fit_Button          (autofit column width, binds to sheet button)
'   - RefreshCache_Button (refresh master cache)
'   - RunValidationSilent (validate sheet, returns row count or -1)
'   - HandleError         (centralized error handler)
' Private Methods:
'   - ValidateKukanCache
'   - UpdateByMaster
'   - Fit_Button
' ============================================================

Sub RefreshCache_Button()
    On Error GoTo ErrorHandler
    Dim activeSheetName As String: activeSheetName = ActiveSheet.CodeName

    Debug.Print "1. Validate Z1~Z4, T1~T3, O1~O3 master data"
    Dim cacheSheets As Variant: cacheSheets = Array(CACHE_Z1, CACHE_Z2, CACHE_Z3, CACHE_Z4, CACHE_T1, CACHE_T2, CACHE_T3, CACHE_O1, CACHE_O2, CACHE_O3)
    Dim sheetName As Variant
    Dim ws As Worksheet
    For Each sheetName In cacheSheets
        Set ws = ThisWorkbook.Worksheets(CStr(sheetName))
        Dim result As Long: result = RunValidationSilent(ws)
        If result = 0 Then
            Err.Raise ERR_CACHE_EMPTY, "RefreshCache_Button", sheetName & " sheet has no data."
        End If
        If result < 0 Then
            Err.Raise ERR_CACHE_EMPTY, "RefreshCache_Button", "Can't refresh " & sheetName & " cache. Validation error occurs."
        End If
    Next sheetName
    
    Debug.Print "2. refresh master data"
    Call RefreshMasterCache()

    Debug.Print "3. Determine which cache sheets to refresh based on ActiveSheet"
    If activeSheetName = "C1" Then
        ' first is M1
        Call ValidateKukanCache("M1")
        Call RefreshKukanCache("M1")
        Call UpdateByMaster("M1")
        ' second is M2
        Call ValidateKukanCache("M2")
        Call RefreshKukanCache("M2")
        Call UpdateByMaster("M2")
    ElseIf activeSheetName = "M2" Then
        Call ValidateKukanCache("M1")
        Call RefreshKukanCache("M1")
        Call UpdateByMaster("M1")
    End If

    Debug.Print "4. update content by other master data"
    Call UpdateByMaster(activeSheetName)

    Exit Sub

ErrorHandler:
    Debug.Print "sheetName = " & sheetName
    HandleError "RefreshCache_Button"
End Sub

Private Sub ValidateKukanCache(ByVal sheetName As String)
    Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets(CStr(sheetName))
    Dim result As Long: result = RunValidationSilent(ws)

    If result = 0 Then
        Err.Raise ERR_CACHE_EMPTY, "ValidateKukanCache", sheetName & " sheet has no data."
    End If

    If result = -1 Then
        Err.Raise ERR_VALIDATION_FAILED, "ValidateKukanCache", "Validation error in " & sheetName & " sheet."
    End If
End Sub

Private Sub UpdateByMaster(ByVal sheetName As String)
    Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets(CStr(sheetName))

    Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
    Dim sheetConf As Object: Set sheetConf = sheetConfDict(sheetName)
    Dim startRow As Long: startRow = sheetConf("StartRow")
    Dim lastDataRow As Long: lastDataRow = GetLastDataRowInRange(ws)
    Application.Run sheetName & ".Refresh", ws, startRow, lastDataRow
End Sub

' ============================================================
' CSV Import entry point (binds to sheet button)
' ============================================================
Public Sub CSV_Import_Button()
    Dim ws As Worksheet: Set ws = ActiveSheet
    On Error GoTo ErrorHandler

    ' Step 1: get csv encoding
    Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
    Dim cfg As Object: Set cfg = sheetConfDict(ws.CodeName)
    Dim expectedColumnCount As Long: expectedColumnCount = cfg("ExpectedColumnCount")

    ' Step 2: Select CSV file
    Dim filePath As String: filePath = SelectCSVFile()
    If filePath = "" Then Exit Sub
    
    ' Step 3: Read CSV and return 2D array
    Dim csvData As Variant: csvData = ReadCSVAs2DArrayStrict(filePath, expectedColumnCount, cfg("CSV_Encoding"), cfg("HasHeader"))
    
    If Not IsArray(csvData) Or UBound(csvData, 1) < 1 Then
        Err.Raise ERR_FILE_EMPTY, "DO_CSV_Import", "No data in CSV."
    End If

    ' === Step 4: Clear all data rows before import ===
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Call ClearDataRows(ws)

    ' === Step 5: Write CSV data to worksheet ===
    Dim colLetters As Variant: colLetters = cfg("HeaderColumns")
    Dim writeRow As Long: writeRow = cfg("StartRow")
    Dim i As Long
    For i = LBound(csvData, 1) To UBound(csvData, 1)
        Dim j As Long
        For j = 0 To expectedColumnCount - 1
            ws.Cells(writeRow, ws.Range(colLetters(j) & "1").Column).Value = CleanCSVField(CStr(csvData(i, j + 1)))
        Next j
        If cfg.Exists("DisplayCol") Then
            Call BuildDisplayDropdown(ws, writeRow)
        End If
        writeRow = writeRow + 1
    Next i

    MsgBox writeRow - cfg("StartRow") & " rows imported.", vbInformation
    GoTo FinallyExit

ErrorHandler:
    HandleError "DO_CSV_Import"
    GoTo FinallyExit

FinallyExit:
    Application.EnableEvents = True
    Application.ScreenUpdating = True
End Sub

' ============================================================
' Do_Validation entry point (binds to sheet button)
' ============================================================
Public Sub Validation_Button()
    Dim ws As Worksheet: Set ws = ActiveSheet
    On Error GoTo ErrorHandler
    Application.EnableEvents = False

    Dim result As Long: result = RunValidationSilent(ws)
    
    If result = -1 Then
        Err.Raise ERR_VALIDATION_FAILED, "Do_Validation", "Validation has errors."
    End If
    
    If result = 0 Then
        Err.Raise ERR_CACHE_EMPTY, "Do_Validation", "No data to validate."
    End If
    
    If ws.CodeName <> "C1" Then
        RefreshCache(ws.CodeName)
        WriteCachesSheet(ws.CodeName)
    End If

    MsgBox "Validation complete. Success: " & result, vbInformation

    ' step2. ValidateWarn for M1 sheet
    If ws.CodeName = "M1" Then
        Dim lastDataRow As Long: lastDataRow = GetLastDataRowInRange(ws)
        Application.Run "M1.ValidateWarn", ws, lastDataRow
    End If

    Do_Fit_Internal ws

    ' Clear previous error marks before validation
    Dim lastRow As Long: lastRow = GetLastDataRowInRange(ws)
    Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
    Dim sheetConf As Object: Set sheetConf = sheetConfDict(ws.CodeName)
    Dim errCol As Long: errCol = ColNum(CStr(sheetConf("ErrorCol")))
    Dim endCol As Long: endCol = ColNum(CStr(sheetConf("EndCol")))
    ws.Range(ws.Cells(lastRow + 1, errCol), ws.Cells(1048576, errCol)).ClearContents
    ws.Range(ws.Cells(lastRow + 1, errCol), ws.Cells(1048576, endCol)).Interior.Color = RGB(255, 255, 255)

    Application.EnableEvents = True
    Do_Fit_Internal ws
    Exit Sub

ErrorHandler:
    Application.EnableEvents = True
    HandleError "Do_Validation"
    Do_Fit_Internal ws

End Sub

' ============================================================
' CSV Export entry point (binds to sheet button)
' ============================================================
Public Sub CSV_Export_Button()
    Dim ws As Worksheet: Set ws = ActiveSheet
    On Error GoTo ErrorHandler

    ' === Step 1: Validate all rows before export ===
    Dim result As Long: result = RunValidationSilent(ws)

    If result = 0 Then
        Err.Raise ERR_CACHE_EMPTY, "DO_CSV_Export", "No data rows to output."
    End If

    If result < 0 Then
        Err.Raise ERR_VALIDATION_FAILED, "DO_CSV_Export", "Validation failed. Export aborted."
    End If

    ' === Step 2: Select save path ===
    Dim savePath As String: savePath = GetSaveCSVPath()
    If savePath = "" Then Exit Sub

    Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
    Dim sheetConf As Object: Set sheetConf = sheetConfDict(ws.CodeName)

    ' === Step 3: Count data rows ===
    Dim lastDataRow As Long: lastDataRow = GetLastDataRowInRange(ws)
    Dim startRow As Long: startRow = sheetConf("StartRow")
    Dim rowCount As Long: rowCount = lastDataRow - startRow + 1

    ' === Step 4: Count data columns ===
    Dim expectedColumnCount As Long: expectedColumnCount = sheetConf("ExpectedColumnCount")

    ' === Step 5: check export csv has header ===
    Dim hasHeader As Boolean: hasHeader = sheetConf("HasHeader")
    Dim dataRow As Long: dataRow = 1
    Dim outputArr As Variant
    
    If hasHeader Then
      ReDim outputArr(1 To rowCount + 1, 1 To expectedColumnCount)
    Else
      ReDim outputArr(1 To rowCount, 1 To expectedColumnCount)
    End If

    ' === Step 6: Build array with header and data ===
    If hasHeader Then
      Dim headerArr As Variant
      headerArr = GetCSVHeader(ws)

      Dim colIdx As Long
      For colIdx = 0 To expectedColumnCount - 1
          outputArr(1, colIdx + 1) = headerArr(1, colIdx + 1)
      Next colIdx
      dataRow = dataRow + 1
    End If
    
    Dim colLetters As Variant: colLetters = sheetConf("HeaderColumns")
    Dim r As Long
    Dim colIndex As Long
    For r = startRow To lastDataRow
        For colIdx = 0 To expectedColumnCount - 1
            colIndex = Columns(colLetters(colIdx)).Column
            outputArr(dataRow, colIdx + 1) = CleanCSVField(ws.Cells(r, colIndex).Value)
        Next colIdx
        dataRow = dataRow + 1
    Next r

    Call WriteCSVFromArray(savePath, outputArr, sheetConf("CSV_Encoding"), sheetConf("AlwaysQuote"))

    MsgBox "CSV export completed. Total data rows: " & rowCount, vbInformation
    Exit Sub

ErrorHandler:
    HandleError "DO_CSV_Export"
End Sub


' ============================================================
' Do_Sort entry point (binds to sheet button)
' ============================================================
Public Sub Sort_Button()
    Dim ws As Worksheet: Set ws = ActiveSheet
    On Error GoTo ErrorHandler

    Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
    Dim sheetConf As Object: Set sheetConf = sheetConfDict(ws.CodeName)

    Dim startCol As String: startCol = sheetConf("StartCol")
    Dim endCol As String: endCol = sheetConf("EndCol")
    Dim startRow As Long: startRow = sheetConf("StartRow")
    Dim lastDataRow As Long: lastDataRow = GetLastDataRowInRange(ws)

    If lastDataRow < startRow Then
        Err.Raise ERR_CACHE_EMPTY, "Do_Sort", "No data to sort."
    End If

    Dim sortRange As Range: Set sortRange = ws.Range(ws.Cells(startRow, ws.Range(startCol & "1").Column), ws.Cells(lastDataRow, ws.Range(endCol & "1").Column))
    Application.Goto sortRange
    Application.Dialogs(xlDialogSort).Show
    Exit Sub

ErrorHandler:
    HandleError "Do_Sort"
End Sub


' ============================================================
' Do_Filter entry point (binds to sheet button)
' ============================================================
Public Sub Filter_Button()
    Dim ws As Worksheet: Set ws = ActiveSheet
    On Error GoTo ErrorHandler

    Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
    Dim sheetConf As Object: Set sheetConf = sheetConfDict(ws.CodeName)

    ' Check if auto filter is already on
    If ws.AutoFilterMode Then
        ws.AutoFilterMode = False
        Exit Sub
    End If

    Dim startCol As Long: startCol = ws.Range(sheetConf("ErrorCol") & "1").Column
    Dim endCol As Long: endCol = ws.Range(sheetConf("EndCol") & "1").Column

    Dim filterRow As Long: filterRow = sheetConf("FilterRow")

    Dim filterRange As Range: Set filterRange = ws.Range(ws.Cells(filterRow, startCol), ws.Cells(filterRow, endCol))
    filterRange.AutoFilter
    Exit Sub

ErrorHandler:
    HandleError "Do_Filter"
End Sub

Public Sub Fit_Button()
    Do_Fit_Internal ActiveSheet
End Sub

' ============================================================
' Do_Fit internal implementation
' ============================================================
Private Sub Do_Fit_Internal(ws As Excel.Worksheet)
    On Error GoTo ErrorHandler

    Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
    Dim sheetConf As Object: Set sheetConf = sheetConfDict(ws.CodeName)

    ' adjust width function contains error column
    Dim startCol As String: startCol = sheetConf("ErrorCol")
    Dim endCol As String: endCol = sheetConf("EndCol")

    ws.Columns(startCol & ":" & endCol).AutoFit
    Exit Sub

ErrorHandler:
    HandleError "Do_Fit"
End Sub

' ============================================================
' RunValidationSilent
' Returns:
'   - Positive number = success (number of rows validated)
'   - 0 = no data
'   - -1 = has errors
' ============================================================
Public Function RunValidationSilent(ws As Worksheet) As Long
    Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
    Dim sheetConf As Object: Set sheetConf = sheetConfDict(ws.CodeName)

    Dim validate As String: validate = ws.CodeName & ".Validate"
    Dim lastDataRow As Long: lastDataRow = GetLastDataRowInRange(ws)
    Dim startRow As Long: startRow = sheetConf("StartRow")
    Dim errorCol As Long: errorCol = ws.Range(sheetConf("ErrorCol") & "1").Column

    If lastDataRow < startRow Then
        RunValidationSilent = 0
        Exit Function
    End If

    Dim r As Long
    Dim hasError As Boolean: hasError = False
    For r = startRow To lastDataRow
        SetLastErrorMsg ""
                Application.Run validate, ws, r, lastDataRow
                If GetLastErrorMsg() <> "" Then
                    Err.Raise ERR_VALIDATION_FAILED, "RunValidationSilent", GetLastErrorMsg()
        End If
        Dim errorMessage As String: errorMessage = Trim(ws.Cells(r, errorCol).Value)
        Dim errorCode As String: errorCode = GetCode(errorMessage)
        If errorCode <> "W001" And errorCode <> "" Then
            hasError = True
        End If
    Next r

    If hasError = True Then
        RunValidationSilent = -1
        Exit Function
    End If

    RunValidationSilent = lastDataRow - startRow + 1
    Exit Function
End Function

' ============================================================
' Error Handlers
' ============================================================

' Main error handler - centralized error processing
Public Sub HandleError(Optional ByVal sourceProcedure As String = "")
    Dim shortCode As String: shortCode = Right("0000" & CStr(Err.Number - vbObjectError), 4)
    MsgBox "[ERROR] " & shortCode & " : " & Err.Description, vbExclamation
End Sub
