Option Explicit

' =========================================================
' [메인 프로시저]
' 폴더 안의 Word 회의록 파일을 읽어서 Excel "회의록" 시트에 누적하고,
' 이미 처리한 파일은 "파일로그" 시트를 기준으로 다시 처리하지 않는다.
' =========================================================
Public Sub Import_Word_MeetingMinutes()

    ' -----------------------------------------------------
    ' (0) 기본 변수 선언
    ' -----------------------------------------------------
    Dim wsData As Worksheet
    Dim wsLog As Worksheet
    
    Dim folderPath As String
    Dim fileName As String
    Dim fullPath As String
    
    Dim wordApp As Object
    Dim wordDoc As Object
    
    Dim processedDict As Object
    Dim itemDict As Object
    
    Dim processedCount As Long
    Dim skippedCount As Long
    Dim errorCount As Long
    
    Dim startTime As Double
    
    On Error GoTo EH
    
    startTime = Timer
    
    Debug.Print String(80, "=")
    Debug.Print "[DEBUG] 작업 시작: " & Format(Now, "yyyy-mm-dd hh:nn:ss")
    
    ' -----------------------------------------------------
    ' (1) 작업 속도 향상을 위한 Excel 환경 설정
    '     화면 갱신, 이벤트, 자동 계산을 잠시 끈다.
    '     대량 파일 처리 시 속도 향상에 도움이 된다.
    ' -----------------------------------------------------
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.DisplayAlerts = False
    Application.Calculation = xlCalculationManual
    
    Debug.Print "[DEBUG] Excel 환경 설정 완료"
    
    ' -----------------------------------------------------
    ' (2) 필수 시트 설정
    '     사용자가 설명한 구조에 따라 "회의록", "파일로그" 시트를 사용한다.
    ' -----------------------------------------------------
    Set wsData = ThisWorkbook.Worksheets("회의록")
    Set wsLog = ThisWorkbook.Worksheets("파일로그")
    
    Debug.Print "[DEBUG] 회의록 시트 확인: " & wsData.Name
    Debug.Print "[DEBUG] 파일로그 시트 확인: " & wsLog.Name
    
    ' -----------------------------------------------------
    ' (3) 사용자가 Word 파일 폴더를 선택한다.
    '     선택을 취소하면 작업을 종료한다.
    ' -----------------------------------------------------
    folderPath = SelectFolderPath()
    
    If Len(folderPath) = 0 Then
        Debug.Print "[DEBUG] 사용자가 폴더 선택을 취소했습니다."
        MsgBox "폴더 선택이 취소되었습니다.", vbInformation
        GoTo CleanExit
    End If
    
    Debug.Print "[DEBUG] 선택된 폴더: " & folderPath
    
    ' -----------------------------------------------------
    ' (4) 파일로그 시트의 기존 처리 파일명을 Dictionary로 만든다.
    '     파일명이 이미 Dictionary에 있으면 다시 처리하지 않는다.
    ' -----------------------------------------------------
    Set processedDict = GetProcessedFileDict(wsLog)
    
    Debug.Print "[DEBUG] 기존 처리 파일 수: " & processedDict.Count
    
    ' -----------------------------------------------------
    ' (5) Word 프로그램을 한 번만 실행한다.
    '     파일마다 Word를 새로 실행하면 속도가 느리므로,
    '     Word Application은 한 번만 열고 문서만 순차적으로 열고 닫는다.
    ' -----------------------------------------------------
    Set wordApp = CreateObject("Word.Application")
    wordApp.Visible = False
    
    Debug.Print "[DEBUG] Word Application 실행 완료"
    
    ' -----------------------------------------------------
    ' (6) 선택 폴더 안의 Word 파일을 순차 처리한다.
    '     docx, docm, doc 파일을 대상으로 한다.
    ' -----------------------------------------------------
    fileName = Dir(folderPath & "\*.doc*")
    
    Do While Len(fileName) > 0
    
        fullPath = folderPath & "\" & fileName
        
        Debug.Print String(80, "-")
        Debug.Print "[DEBUG] 확인 중인 파일: " & fileName
        
        ' -------------------------------------------------
        ' (6-1) 임시 Word 파일은 제외한다.
        '       Word에서 열려 있는 문서가 있을 때 ~$ 로 시작하는 임시 파일이 생길 수 있다.
        ' -------------------------------------------------
        If Left(fileName, 2) = "~$" Then
        
            Debug.Print "[DEBUG] 임시 파일이므로 건너뜀: " & fileName
            skippedCount = skippedCount + 1
            
        ' -------------------------------------------------
        ' (6-2) 이미 처리한 파일이면 건너뛴다.
        '       "파일로그" 시트 A열에 같은 파일명이 있으면 처리하지 않는다.
        ' -------------------------------------------------
        ElseIf processedDict.Exists(fileName) Then
        
            Debug.Print "[DEBUG] 이미 처리된 파일이므로 건너뜀: " & fileName
            skippedCount = skippedCount + 1
            
        Else
        
            On Error GoTo FileEH
            
            Debug.Print "[DEBUG] 신규 파일 처리 시작: " & fileName
            
            ' ---------------------------------------------
            ' (6-3) Word 문서를 읽기 전용으로 연다.
            '       읽기 전용으로 열어 원본 문서가 수정되지 않도록 한다.
            ' ---------------------------------------------
            Set wordDoc = wordApp.Documents.Open( _
                            FileName:=fullPath, _
                            ReadOnly:=True, _
                            AddToRecentFiles:=False, _
                            Visible:=False)
            
            Debug.Print "[DEBUG] Word 문서 열기 완료: " & fileName
            
            ' ---------------------------------------------
            ' (6-4) Word 표 내용을 Dictionary로 읽는다.
            '       1열은 항목명, 2열은 값으로 처리한다.
            ' ---------------------------------------------
            Set itemDict = ReadWordTableToDict(wordDoc)
            
            Debug.Print "[DEBUG] Word 표 항목 수: " & itemDict.Count
            
            ' ---------------------------------------------
            ' (6-5) 회의록 시트에 한 건 입력한다.
            '       회의일 기준 오름차순 위치를 찾아 행을 삽입한 뒤 입력한다.
            ' ---------------------------------------------
            InsertMeetingRecord wsData, itemDict
            
            Debug.Print "[DEBUG] 회의록 시트 입력 완료: " & fileName
            
            ' ---------------------------------------------
            ' (6-6) 파일로그 시트에 처리 완료 이력을 기록한다.
            '       A열에는 파일명, B열에는 불러온 날짜를 기록한다.
            ' ---------------------------------------------
            AppendFileLog wsLog, fileName, Now
            
            Debug.Print "[DEBUG] 파일로그 기록 완료: " & fileName
            
            ' ---------------------------------------------
            ' (6-7) 이번 실행 중 같은 파일이 다시 나오지 않도록
            '       Dictionary에도 즉시 추가한다.
            ' ---------------------------------------------
            processedDict.Add fileName, True
            
            ' ---------------------------------------------
            ' (6-8) Word 문서를 닫는다.
            '       저장하지 않고 닫는다.
            ' ---------------------------------------------
            wordDoc.Close SaveChanges:=False
            Set wordDoc = Nothing
            
            processedCount = processedCount + 1
            
            Debug.Print "[DEBUG] 신규 파일 처리 완료: " & fileName
            
            On Error GoTo EH
            
        End If
        
NextFile:
        fileName = Dir()
        
    Loop
    
    ' -----------------------------------------------------
    ' (7) 전체 입력 후 서식을 정리한다.
    '     자동줄바꿈을 적용하고 행 높이를 자동 조정한다.
    ' -----------------------------------------------------
    ApplyMeetingSheetFormat wsData
    
    Debug.Print "[DEBUG] 회의록 시트 서식 정리 완료"
    
    ' -----------------------------------------------------
    ' (8) 처리 결과 안내
    ' -----------------------------------------------------
    Debug.Print String(80, "=")
    Debug.Print "[DEBUG] 작업 종료: " & Format(Now, "yyyy-mm-dd hh:nn:ss")
    Debug.Print "[DEBUG] 신규 처리 파일 수: " & processedCount
    Debug.Print "[DEBUG] 건너뛴 파일 수: " & skippedCount
    Debug.Print "[DEBUG] 오류 파일 수: " & errorCount
    Debug.Print "[DEBUG] 총 소요 시간(초): " & Format(Timer - startTime, "0.00")
    
    MsgBox "작업이 완료되었습니다." & vbCrLf & vbCrLf & _
           "신규 처리 파일 수: " & processedCount & vbCrLf & _
           "건너뛴 파일 수: " & skippedCount & vbCrLf & _
           "오류 파일 수: " & errorCount, vbInformation

CleanExit:
    ' -----------------------------------------------------
    ' (9) Word Application 종료
    '     문서가 열려 있으면 저장하지 않고 닫고,
    '     Word 프로그램도 종료한다.
    ' -----------------------------------------------------
    On Error Resume Next
    
    If Not wordDoc Is Nothing Then
        wordDoc.Close SaveChanges:=False
    End If
    
    If Not wordApp Is Nothing Then
        wordApp.Quit
    End If
    
    Set wordDoc = Nothing
    Set wordApp = Nothing
    
    ' -----------------------------------------------------
    ' (10) Excel 환경 설정 복구
    '      오류가 나더라도 반드시 원래 상태로 되돌린다.
    ' -----------------------------------------------------
    Application.ScreenUpdating = True
    Application.EnableEvents = True
    Application.DisplayAlerts = True
    Application.Calculation = xlCalculationAutomatic
    Application.StatusBar = False
    
    Debug.Print "[DEBUG] Excel 환경 설정 복구 완료"
    Debug.Print String(80, "=")
    
    Exit Sub

FileEH:
    ' -----------------------------------------------------
    ' (11) 개별 파일 처리 중 오류가 발생한 경우
    '      전체 작업을 중단하지 않고 다음 파일로 넘어간다.
    ' -----------------------------------------------------
    errorCount = errorCount + 1
    
    Debug.Print "[ERROR] 파일 처리 중 오류 발생"
    Debug.Print "[ERROR] 파일명: " & fileName
    Debug.Print "[ERROR] 오류 번호: " & Err.Number
    Debug.Print "[ERROR] 오류 내용: " & Err.Description
    
    On Error Resume Next
    
    If Not wordDoc Is Nothing Then
        wordDoc.Close SaveChanges:=False
        Set wordDoc = Nothing
    End If
    
    Err.Clear
    On Error GoTo EH
    
    Resume NextFile

EH:
    ' -----------------------------------------------------
    ' (12) 전체 작업 중 치명적 오류가 발생한 경우
    '      오류 내용을 Immediate 창에 남기고 종료 처리로 이동한다.
    ' -----------------------------------------------------
    Debug.Print "[FATAL] 전체 작업 중 오류 발생"
    Debug.Print "[FATAL] 오류 번호: " & Err.Number
    Debug.Print "[FATAL] 오류 내용: " & Err.Description
    
    MsgBox "작업 중 오류가 발생했습니다." & vbCrLf & vbCrLf & _
           "오류 번호: " & Err.Number & vbCrLf & _
           "오류 내용: " & Err.Description, vbExclamation
    
    Resume CleanExit

End Sub


' =========================================================
' [함수] 폴더 선택 대화상자
' 사용자가 Word 파일이 들어 있는 폴더를 선택하도록 한다.
' =========================================================
Private Function SelectFolderPath() As String

    Dim fd As FileDialog
    
    On Error GoTo EH
    
    ' -----------------------------------------------------
    ' (1) 폴더 선택 대화상자를 만든다.
    ' -----------------------------------------------------
    Set fd = Application.FileDialog(msoFileDialogFolderPicker)
    
    With fd
        .Title = "취합할 Word 회의록 파일이 들어 있는 폴더를 선택하세요."
        .AllowMultiSelect = False
        
        ' -------------------------------------------------
        ' (2) 사용자가 폴더를 선택하면 경로를 반환한다.
        '     선택을 취소하면 빈 문자열을 반환한다.
        ' -------------------------------------------------
        If .Show = -1 Then
            SelectFolderPath = .SelectedItems(1)
        Else
            SelectFolderPath = vbNullString
        End If
    End With
    
    Exit Function

EH:
    Debug.Print "[ERROR] 폴더 선택 중 오류: " & Err.Number & " / " & Err.Description
    SelectFolderPath = vbNullString

End Function


' =========================================================
' [함수] 파일로그 Dictionary 생성
' "파일로그" 시트 A열에 기록된 파일명을 Dictionary로 만든다.
' =========================================================
Private Function GetProcessedFileDict(ByVal wsLog As Worksheet) As Object

    Dim dict As Object
    Dim lastRow As Long
    Dim r As Long
    Dim fileName As String
    
    Set dict = CreateObject("Scripting.Dictionary")
    dict.CompareMode = vbTextCompare
    
    ' -----------------------------------------------------
    ' (1) 파일로그 A열의 마지막 행을 찾는다.
    ' -----------------------------------------------------