' ============================================================
' Module Name: Master_Kukan_detail
' Module Desc: M2 Kukan detail master data management
' Module Methods:
'   - Worksheet_Change
'   - FillFromM1
'   - validateButton_Click
'   - Validate
' ============================================================
Private Sub Worksheet_Change(ByVal Target As Range)
    Dim HasHeaderEdit As Boolean: HasHeaderEdit = CheckHeaderEdit(Me, Target)
    If HasHeaderEdit = True Then Exit Sub

    If Target.EntireRow.Address = Target.Address Then Exit Sub

    Dim watchArea As Range
    With Me
        Set watchArea = Union( _
            .Columns("C"), _
            .Columns("I:R") _
        )
    End With
    Dim intersectRng As Range: Set intersectRng = Application.Intersect(Target, watchArea)
    If intersectRng Is Nothing Then Exit Sub

    If Target.Row < 7 Then Exit Sub

    Application.EnableEvents = False
    On Error GoTo Finally

    ' === Fill D, E when C column changes ===
    If Target.Column = 3 Then
        Dim cell As Range
        For Each cell In Target
            If Trim(cell.Value) = "" Then
                Call ClearRowData(Me, cell.Row)
                GoTo Finally
            Else
                Call FillFromM1(Me, cell.Row)
                Call BuildKenshuDropdown(Me, "I", cell.Row)
            End If
        Next
    End If
    
    ' === Create J dropdown when I column changes ===
    If Target.Column = 9 Then
        Dim cellI As Range
        For Each cellI In Target
            ' Store key only (e.g., "1") in I column
            Dim kenshuKey As String: kenshuKey = GetCode(cellI.Value)
            If kenshuKey <> "" Then
                cellI.Value = kenshuKey
            End If
            ' clear
            Me.Range(Me.Cells(cellI.Row, 10), Me.Cells(cellI.Row, 18)).ClearContents
            Me.Range(Me.Cells(cellI.Row, 10), Me.Cells(cellI.Row, 18)).Interior.Color = vbWhite
            Me.Cells(cellI.Row, 10).Validation.Delete
            Call CreateJDropdown(cellI.Row)
            Call ChangeBackColor(cellI.Row)
        Next
    End If
    
    ' === Fill K column when J column changes ===
    If Target.Column = 10 Then
        Dim cellJ As Range
        For Each cellJ In Target
            Call FillKFromJ(Me, cellJ.Row)
        Next
    End If

    Dim kenshuKbn As String: kenshuKbn = Trim(Me.Range("I" & Target.Row).Value)
    Dim restrictedCols As Range
    If kenshuKbn = "1" Then
        Set restrictedCols = Union(Me.Columns("K"), Me.Columns("O"), Me.Columns("P"), Me.Columns("Q"), Me.Columns("R"))
        If Not Intersect(Target, restrictedCols) Is Nothing Then
            Application.EnableEvents = False
            MsgBox "can not be input", vbExclamation
            Application.Undo
            Application.EnableEvents = True
            Exit Sub
        End If
    Else
        Set restrictedCols = Me.Range("K:R") '
        If Not Intersect(Target, restrictedCols) Is Nothing Then
            Application.EnableEvents = False
            MsgBox "can not be input", vbExclamation
            Application.Undo
            Application.EnableEvents = True
            Exit Sub
        End If
    End If

Finally:
    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"
        .AddCodeSelect "C", CACHE_M1
        .AddRequired "I"
        .AddRequired "J"
        .AddRequired "K"
        .AddRequired "L"
        .AddRequired "M"
        .AddNumber "L", 10, 3
        .AddNumber "M", 7, 0
        .AddNumber "N", 3, 0
        .AddNumber "O"
        .AddNumber "P"
        .AddNumber "Q"
        .AddNumber "R"
    End With

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

    ' === Special cases (cross-cache / cross-column) ===
    If result.ErrorCode <> "" Then Exit Sub

    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)

    ' J: must exist in T1/T2/T3 cache (determined by I column)
    Dim kenshuKbn As String: kenshuKbn = Trim(ws.Range("I" & rowNum).Value)
    Dim cache As Object
    Select Case kenshuKbn
        Case "1": Set cache = GetCache(CACHE_T1)
        Case "2": Set cache = GetCache(CACHE_T2)
        Case "3": Set cache = GetCache(CACHE_T3)
        Case Else
            errorCell.Value = GetErrorMsg(ERR_NOT_EXIST, "I" & rowNum)
            ws.Range("I" & rowNum).Interior.Color = RGB(255, 0, 0)
            Exit Sub
    End Select

    Dim kukanCode As String: kukanCode = Trim(ws.Range("C" & rowNum).Value)
    Dim code As String: code = Trim(ws.Range("J" & rowNum).Value)
    If Not cache.Exists(code) Then
        errorCell.Value = GetErrorMsg(ERR_NOT_EXIST, "J" & rowNum)
        ws.Range("J" & rowNum).Interior.Color = RGB(255, 0, 0)
        Exit Sub
    End If

    ' kenshuKbn-specific: equaledCols, requiredCols, emptyCols
    Dim equaledCols As Variant
    Dim requiredCols As Variant
    Dim emptyCols As Variant
    If kenshuKbn = "1" Then
        equaledCols = Array("K")
        requiredCols = Array("N")
        emptyCols = Array("O", "P", "Q", "R")
    ElseIf kenshuKbn = "2" Then
        equaledCols = Array("K", "L", "M", "N", "O", "P", "Q")
        requiredCols = Array("N", "O", "P", "Q")
        emptyCols = Array("R")
    ElseIf kenshuKbn = "3" Then
        equaledCols = Array("K", "L", "M")
        requiredCols = Array()
        emptyCols = Array("N", "O", "P", "Q", "R")
    End If

    ' equaledCols must match cache values
    Dim equaledIndex As Long
    For equaledIndex = LBound(equaledCols) To UBound(equaledCols)
        Dim equaledCol As String: equaledCol = equaledCols(equaledIndex)
        Dim equalValue As String: equalValue = Trim(ws.Range(equaledCol & rowNum).Value)
        If cache(code)(equaledIndex) <> equalValue Then
            errorCell.Value = GetErrorMsg(ERR_INVALID, equaledCol & rowNum)
            ws.Range(equaledCol & rowNum).Interior.Color = RGB(255, 0, 0)
            Exit Sub
        End If
    Next equaledIndex

    ' requiredCols must not be empty
    Dim requiredCol As Variant
    For Each requiredCol In requiredCols
        Dim requiredValue As String: requiredValue = Trim(ws.Range(requiredCol & rowNum).Value)
        If requiredValue = "" Then
            errorCell.Value = GetErrorMsg(ERR_REQUIRED, requiredCol & rowNum)
            ws.Range(requiredCol & rowNum).Interior.Color = RGB(255, 0, 0)
            Exit Sub
        End If
    Next requiredCol

    ' emptyCols must be empty
    Dim emptyCol As Variant
    For Each emptyCol In emptyCols
        Dim emptyValue As String: emptyValue = Trim(ws.Range(emptyCol & rowNum).Value)
        If emptyValue <> "" Then
            errorCell.Value = GetErrorMsg("E005", emptyCol & rowNum)
            ws.Range(emptyCol & rowNum).Interior.Color = RGB(255, 0, 0)
            Exit Sub
        End If
    Next emptyCol

    ' Duplicate: C + I + J (+ N if kenshuKbn=1)
    Dim sikyuKikan As String: sikyuKikan = Trim(ws.Range("N" & rowNum).Value)
    Dim hasError As Boolean: hasError = False
    Dim otherValueC As String, otherValueI As String, otherValueJ As String, otherValueN As String
    Dim otherRow As Long
    If rowNum < 9 Then
        Call ChangeBackColor(rowNum)
        Exit Sub
    End If

    For otherRow = 8 To rowNum - 1
        otherValueC = Trim(ws.Cells(otherRow, "C").Value)
        otherValueI = Trim(ws.Cells(otherRow, "I").Value)
        otherValueJ = Trim(ws.Cells(otherRow, "J").Value)
        otherValueN = Trim(ws.Cells(otherRow, "N").Value)
        If kenshuKbn = "1" Then
            If otherValueC = kukanCode And otherValueI = kenshuKbn And otherValueJ = code And otherValueN = sikyuKikan Then
                hasError = True
            End If
        Else
            If otherValueC = kukanCode And otherValueI = kenshuKbn And otherValueJ = code Then
                hasError = True
            End If
        End If

        If hasError = True Then
            errorCell.Value = GetErrorMsg("E013", otherRow, code)
            ws.Cells(rowNum, "C").Interior.Color = RGB(255, 0, 0)
            Exit Sub
        End If
    Next otherRow
    
    Call ChangeBackColor(rowNum)
    
    Exit Sub
ErrHandler:
    SetLastErrorMsg Err.Description
End Sub

' obtain T1/T2/T3 cache data, and update column K
Private Sub Refresh(ws As Worksheet, ByVal startRow As Long, ByVal lastDataRow As Long)
    Dim kenshuList As Object: Set kenshuList = GetCache("kenshuList")
    
    Application.EnableEvents = False
    On Error GoTo ErrorHandler
    
    Dim r As Long
    For r = startRow To lastDataRow
        Dim cValue As String: cValue = Trim(ws.Cells(r, 3).Value) ' Column C
        
        ' Skip if C column is empty
        If cValue = "" Then
            GoTo NextRow
        End If
        
        ' Reuse FillFromM1 method to fill D-H columns
        Call FillFromM1(ws, r)
        Call BuildKenshuDropdown(ws, "I", r)
        
        ' Reuse FillKFromJ method to fill J-K columns
        Dim iValue As String: iValue = Trim(ws.Cells(r, 9).Value) ' Column I
        If iValue <> "" And kenshuList.Exists(iValue) Then
            Call CreateJDropdown(r)
            Call ChangeBackColor(r)
            Call FillKFromJ(ws, r)
        End If
        
NextRow:
    Next r
    
    Application.EnableEvents = True
    Exit Sub

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

Private Sub FillKFromJ(ByVal ws As Worksheet, ByVal rowNum As Long)
    Dim kenshu As String: kenshu = Trim(ws.Range("I" & rowNum).Value)
    Dim jValue As String: jValue = Trim(ws.Range("J" & rowNum).Value)
    Dim code As String: code = GetCode(jValue)
    
    If jValue = "" Then
        ws.Range(ws.Cells(rowNum, "K"), ws.Cells(rowNum, "R")).ClearContents
        Exit Sub
    End If
    
    ' Get cache based on I column value
    Dim cache As Object
    Select Case kenshu
        Case "1"
            Set cache = GetCache(CACHE_T1)
        Case "2"
            Set cache = GetCache(CACHE_T2)
        Case "3"
            Set cache = GetCache(CACHE_T3)
        Case Else
            Exit Sub
    End Select
    
    If cache Is Nothing Then Exit Sub
    
    ' Check if J value exists in cache
    If cache.Exists(code) Then
        Dim cacheVal As Variant: cacheVal = cache(code)
        ws.Range("J" & rowNum).Value = Trim(code)
        ws.Range("K" & rowNum).Value = Trim(cacheVal(0))
    End If

    Select Case kenshu
        Case "1"
            Exit Sub
        Case "2"
            ws.Range("L" & rowNum).Value = Trim(cacheVal(1))
            ws.Range("M" & rowNum).Value = Trim(cacheVal(2))
            ws.Range("N" & rowNum).Value = Trim(cacheVal(3))
            ws.Range("O" & rowNum).Value = Trim(cacheVal(4))
            ws.Range("P" & rowNum).Value = Trim(cacheVal(5))
            ws.Range("Q" & rowNum).Value = Trim(cacheVal(6))
        Case "3"
            ws.Range("L" & rowNum).Value = Trim(cacheVal(1))
            ws.Range("M" & rowNum).Value = Trim(cacheVal(2))
        Case Else
            Exit Sub
    End Select
    
End Sub

Private Sub FillFromM1(ByVal ws As Worksheet, ByVal rowNum As Long)
    Dim m1Cache As Object: Set m1Cache = GetCache("M1")
    Dim cValue As String: cValue = Trim(ws.Range("C" & rowNum).Value)

    ' Fill D, E, F, G, H columns from M1 cache
    ' D = cache[1]: cache[2]  (col 4: col 5)
    ' E = cache[3]            (col 6)
    ' F = cache[4]            (col 7)
    ' G = cache[5]            (col 9)
    ' H = cache[6]            (col 12)

    ' Check C column in the cache
    If Not m1Cache.Exists(cValue) Then
        ws.Cells(rowNum, 4).Value = ""
        ws.Cells(rowNum, 5).Value = ""
        ws.Cells(rowNum, 6).Value = ""
        ws.Cells(rowNum, 7).Value = ""
        ws.Cells(rowNum, 8).Value = ""
        Exit Sub
    End If

    Dim cacheVal As Variant: cacheVal = m1Cache(cValue)
    
    ' D column = cache[1]: cache[2]
    ws.Cells(rowNum, 4).Value = Trim(cacheVal(1)) & ":" & Trim(cacheVal(2))
    ' E column = cache[3]
    ws.Cells(rowNum, 5).Value = Trim(cacheVal(3))
    ' F column = cache[4]
    ws.Cells(rowNum, 6).Value = Trim(cacheVal(4))
    ' G column = cache[5]
    ws.Cells(rowNum, 7).Value = Trim(cacheVal(5))
    ' H column = cache[6]
    ws.Cells(rowNum, 8).Value = Trim(cacheVal(6))
End Sub

Private Sub ClearRowData(ByVal ws As Worksheet, ByVal rowNum As Long)
    ' Clear from D column onwards
    ws.Range(ws.Cells(rowNum, "D"), ws.Cells(rowNum, "R")).ClearContents
    ws.Range(ws.Cells(rowNum, "C"), ws.Cells(rowNum, "R")).Interior.Color = vbWhite
    ws.Cells(rowNum, "J").Validation.Delete
    ws.Cells(rowNum, "S").ClearContents
End Sub

Private Sub CreateJDropdown(ByVal rowNum As Long)
    Dim kenshu As String: kenshu = Trim(Me.Range("I" & rowNum).Value)
    Dim targetCell As Range: Set targetCell = Me.Range("J" & rowNum)
    
    ' Clear existing validation
    targetCell.Validation.Delete
    If kenshu = "" Then
        Exit Sub
    End If 
    Call BuildDropdownFromCacheNamedRange(Me, "J", rowNum, "T" & kenshu)
End Sub

' change back color by I colum kennshu
Private Sub ChangeBackColor(ByVal rowNum As Long)
    Dim kenshu As String: kenshu = Trim(Me.Range("I" & rowNum).Value)
    If kenshu = "" Then
        Exit Sub
    End If 

    Me.Range("R" & rowNum).Interior.Color = RGB(192, 192, 192)
    ' Get cache based on I column value
    Dim cache As Object
    Select Case kenshu
        Case "1"
            Me.Range("O" & rowNum).Interior.Color = RGB(192, 192, 192)
            Me.Range("P" & rowNum).Interior.Color = RGB(192, 192, 192)
            Me.Range("Q" & rowNum).Interior.Color = RGB(192, 192, 192)
        Case "2"
            Exit Sub
        Case "3"
            Me.Range("N" & rowNum).Interior.Color = RGB(192, 192, 192)
            Me.Range("O" & rowNum).Interior.Color = RGB(192, 192, 192)
            Me.Range("P" & rowNum).Interior.Color = RGB(192, 192, 192)
            Me.Range("Q" & rowNum).Interior.Color = RGB(192, 192, 192)
        Case Else
            Exit Sub
    End Select
End Sub
