' ============================================================
' Module Name: Master_Kukan
' Module Desc: M1 Kukan master data management (import/export/validate)
' Module Methods:
'   - CreateEnumDropdown
'   - Worksheet_Change
'   - Validate
' ============================================================

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim HasHeaderEdit As Boolean: HasHeaderEdit = CheckHeaderEdit(Me, Target)
    If HasHeaderEdit = True Then Exit Sub
    
    Application.EnableEvents = False
    On Error GoTo Finally
    
    ' Multi-cell selection not processed
    If Target.Count > 1 Then GoTo Finally
    
    ' === Column C changes: Create L column dropdown ===
    If Target.Column = 3 And Target.Row >= 7 Then
        Dim cell As Range
        For Each cell In Target
            If Trim(cell.Value) = "" Then
                Call ClearDataRow(Me, cell.Row)
            Else
                Call BuildTokubetuDropdown(Me, "L", cell.Row)
                Call BuildRenrakuDropdown(Me, "K", cell.Row)
            End If
        Next
    End If

    ' === Column D changes: Fill E column ===
    If Target.Column = 4 And Target.Row >= 7 Then
        Dim z1Cache As Object: Set z1Cache = GetCache(CACHE_Z1)
        Dim z4Rosen As Object: Set z4Rosen = GetCache(CACHE_Z4ROSEN)
        Dim cellD As Range
        For Each cellD In Target
            Dim dVal As String: dVal = Trim(cellD.Value)
            If dVal = "" Then
                Me.Cells(cellD.Row, 5).ClearContents
                Me.Cells(cellD.Row, 6).ClearContents
                Me.Cells(cellD.Row, 7).ClearContents
                Me.Cells(cellD.Row, 6).Validation.Delete
                Me.Cells(cellD.Row, 7).Validation.Delete
            Else
                If z1Cache.Exists(dVal) Then
                    Dim kikan As Variant: kikan = z1Cache(dVal)
                    Dim kikanName As String: kikanName = kikan(0)
                    Me.Cells(cellD.Row, 5).Value = kikanName

                    If z4Rosen.Exists(kikanName) Then
                        Call BuildZ4StationFromDropdown(Me, "F", cellD.Row, kikanName)
                        Dim stations As Object: Set stations = z4Rosen(kikanName)
                        Dim fromCell As Range: Set fromCell = Me.Cells(cellD.Row, 6)
                        Dim fromStation As String: fromStation = Trim(fromCell.Value)
                        If Not stations.Exists(fromStation) Or fromStation = "" Then
                            fromCell.ClearContents
                            Me.Cells(cellD.Row, 7).ClearContents
                            Me.Cells(cellD.Row, 7).Validation.Delete
                        Else
                            Call BuildZ4StationToDropdown(Me, "G", cellD.Row, kikanName, fromStation)
                            Dim toCell As Range: Set toCell = Me.Cells(cellD.Row, 7)
                            Dim toStation As String: toStation = Trim(toCell.Value)

                            If Not stations.Exists(toStation) Or toStation = "" Then
                                toCell.ClearContents
                            End If
                        End If
                    Else
                        Me.Cells(cellD.Row, 6).ClearContents
                        Me.Cells(cellD.Row, 7).ClearContents
                        Me.Cells(cellD.Row, 6).Validation.Delete
                        Me.Cells(cellD.Row, 7).Validation.Delete
                    End If
                    
                Else
                    Me.Cells(cellD.Row, 5).ClearContents
                    Me.Cells(cellD.Row, 6).ClearContents
                    Me.Cells(cellD.Row, 7).ClearContents
                    Me.Cells(cellD.Row, 6).Validation.Delete
                    Me.Cells(cellD.Row, 7).Validation.Delete
                End If
            End If
            
        Next
    End If

    ' === Column F changes (station from): Build H column (station to) dropdown ===
    If Target.Column = 6 And Target.Row >= 7 Then
        Dim cellF As Range
        For Each cellF In Target
            Dim stationFrom As String: stationFrom = Trim(cellF.Value)
            Dim rosenForH As String: rosenForH = Trim(Me.Cells(cellF.Row, 5).Value)
            If stationFrom = "" Then
                Me.Cells(cellF.Row, 7).ClearContents
                Me.Cells(cellF.Row, 7).Validation.Delete
            Else
                Call BuildZ4StationToDropdown(Me, "G", cellF.Row, rosenForH, stationFrom)
            End If
        Next
    End If

    Application.EnableEvents = True
    Exit Sub

Finally:
    HandleError "Worksheet_Change"
    Application.EnableEvents = True
End Sub

' Prevent insert/delete row in header area
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
    Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
    Dim sheetConf As Object: Set sheetConf = sheetConfDict(Me.CodeName)
    Dim filterRow As Long: filterRow = sheetConf("FilterRow")

    If Target.Row < filterRow + 1 Then
        Cancel = True
        MsgBox "Cannot insert or delete row in header area.", vbExclamation
    End If
End Sub

'
Public Sub Validate(ws As Worksheet, ByVal rowNum As Long, ByVal lastDataRow As Long)
    On Error GoTo ErrHandler

    Dim engine As ValidationRuleEngine: Set engine = New ValidationRuleEngine
    With engine
        .AddRequired "C"
        .AddChar "C", 5
        .AddAlphanumeric "C"
        .AddDuplicate "C"
        .AddRequired "D"
        .AddCodeSelect "D", CACHE_Z1
        .AddRequired "E"
        .AddCodeSelect "E", CACHE_Z4ROSEN
        .AddRequired "F"
        .AddRequired "G"
        .AddRequired "I"
        .AddRequired "L"
        .AddCodeSelect "K", "renrakuList"
        .AddCodeSelect "L", "tokubetuList"
        .AddNumber "H", 6, 1
        .AddNumber "I", 5, 0
        .AddNumber "J", 6, 0
        .AddNumber "N", 7, 0
        
    End With

    Dim result As ValidationResult: Set result = engine.ValidateRow(ws, rowNum, lastDataRow)

    If result.ErrorCode <> "" Then Exit Sub
    ' === Special cases (cross-column / cross-cache) ===
    Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
    Dim sheetConf As Object: Set sheetConf = sheetConfDict(ws.CodeName)
    Dim errorCol As String: errorCol = sheetConf("ErrorCol")
    Dim errorCell As Range: Set errorCell = ws.Cells(rowNum, errorCol)

    ' E: must equal CACHE_Z1(D) value
    Dim z1Cache As Object: Set z1Cache = GetCache(CACHE_Z1)
    Dim dValue As String: dValue = Trim(ws.Range("D" & rowNum).Value)
    Dim valArray As Variant: valArray = z1Cache(dValue)
    Dim expectedE As String: expectedE = Trim(CStr(valArray(0)))
    Dim eValue As String: eValue = Trim(ws.Range("E" & rowNum).Value)
    If eValue <> expectedE Then
        errorCell.Value = GetErrorMsg(ERR_NOT_EXIST, "E" & CStr(rowNum))
        ws.Range("E" & rowNum).Interior.Color = RGB(255, 0, 0)
        Exit Sub
    End If

    ' F, G: must be valid stations in the rosen (E), F cannot equal G
    Dim z4Rosen As Object: Set z4Rosen = GetCache(CACHE_Z4ROSEN)
    Dim stations As Object: Set stations = z4Rosen(eValue)
    Dim fValue As String: fValue = Trim(ws.Range("F" & rowNum).Value)
    Dim gValue As String: gValue = Trim(ws.Range("G" & rowNum).Value)
    If Not stations.Exists(fValue) Then
        errorCell.Value = GetErrorMsg(ERR_NOT_EXIST, "F" & CStr(rowNum))
        ws.Range("F" & rowNum).Interior.Color = RGB(255, 0, 0)
        Exit Sub
    End If
    If Not stations.Exists(gValue) Then
        errorCell.Value = GetErrorMsg(ERR_NOT_EXIST, "G" & CStr(rowNum))
        ws.Range("G" & rowNum).Interior.Color = RGB(255, 0, 0)
        Exit Sub
    End If
    If fValue = gValue Then
        errorCell.Value = GetErrorMsg(ERR_INVALID, "G" & CStr(rowNum))
        ws.Range("F" & rowNum).Interior.Color = RGB(255, 0, 0)
        ws.Range("G" & rowNum).Interior.Color = RGB(255, 0, 0)
        Exit Sub
    End If
    
    Exit Sub
ErrHandler:
    SetLastErrorMsg Err.Description
End Sub

' obtain z1 master data, and update column E
Private Sub Refresh(ws As Worksheet, ByVal startRow As Long, ByVal lastDataRow As Long)
    Dim z1Cache As Object: Set z1Cache = GetCache(CACHE_Z1)
    
    Application.EnableEvents = False
    On Error GoTo ErrorHandler
    
    Dim r As Long
    Dim z4Rosen As Object: Set z4Rosen = GetCache(CACHE_Z4ROSEN)
    For r = startRow To lastDataRow
        Dim dVal As String: dVal = Trim(ws.Cells(r, 4).Value) ' Column D
        If dVal <> "" And z1Cache.Exists(dVal) Then
            Dim valsD As Variant: valsD = z1Cache(dVal)
            ws.Cells(r, 5).Value = valsD(0) ' Column E
            Dim kikanName As String: kikanName = valsD(0)
            If z4Rosen.Exists(kikanName) Then
                Call BuildZ4StationFromDropdown(ws, "F", r, kikanName)
                Dim stationFrom As String: stationFrom = Trim(ws.Cells(r, 6).Value)
                If stationFrom <> "" Then
                    Call BuildZ4StationToDropdown(ws, "G", r, kikanName, stationFrom)
                End If
            End If
        End If
        Call BuildTokubetuDropdown(ws, "L", r)
        Call BuildRenrakuDropdown(ws, "K", r)
    Next r

    Application.EnableEvents = True
    Exit Sub

ErrorHandler:
    Application.EnableEvents = True
    Err.Raise ERR_CACHE_NOT_FOUND, "M1.Refresh", "Failed to refresh M1: " & Err.Description
End Sub

Private Sub ValidateWarn(ws As Worksheet, ByVal lastDataRow As Long)
    On Error GoTo ErrorHandler
    Dim exitMsg As String

    ' Get M2 sheet kukan code list directly
    Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig()
    Dim m2SheetConf As Object: Set m2SheetConf = sheetConfDict(CACHE_M2)
    Dim m2StartRow As Long: m2StartRow = m2SheetConf("StartRow")
    Dim wsM2 As Worksheet: Set wsM2 = ThisWorkbook.Worksheets(CACHE_M2)
    Dim lastRowM2 As Long: lastRowM2 = GetLastDataRowInRange(wsM2)
    If lastRowM2 < m2StartRow Then
        exitMsg = "M2 sheet has no data"
        GoTo ErrorHandler
    End If
    
    ' Build kukan code list from M2 sheet
    Dim kukanList As Object: Set kukanList = CreateObject("Scripting.Dictionary")
    Dim r As Long
    For r = m2StartRow To lastRowM2
        Dim kukanCode As String: kukanCode = Trim(wsM2.Cells(r, 3).Value)
        If kukanCode <> "" And Not kukanList.Exists(kukanCode) Then
            kukanList.Add kukanCode, True
        End If
    Next r

    
    Dim sheetConf As Object: Set sheetConf = sheetConfDict("M1")
    Dim startRow As Long: startRow = sheetConf("StartRow")
    Dim errorCol As String: errorCol = sheetConf("ErrorCol")
    ' Check all rows in M1 sheet
    If lastDataRow < startRow Then
        exitMsg = "M1 sheet has no data"
        GoTo ErrorHandler
    End If
    
    Dim rowNum As Long
    For rowNum = startRow To lastDataRow
        Dim cValue As String: cValue = Trim(ws.Range("C" & rowNum).Value)        
        If Not kukanList.Exists(cValue) Then
            ws.Cells(rowNum, errorCol).Value = GetErrorMsg("W001", cValue)
            ws.Range("C" & rowNum).Interior.Color = RGB(255, 128, 0)
        End If
NextRow:
    Next rowNum
    
    Exit Sub

ErrorHandler:
    If exitMsg <> "" Then
        MsgBox "ValidateWarn: " & exitMsg, vbExclamation
    Else
        MsgBox "ValidateWarn: " & Err.Description, vbExclamation
    End If
End Sub