
Imports System.Data
    Imports System.Data.SqlClient
    Imports System.Globalization
    Imports ClosedXML.Excel

Public Class cTRCustStat

    Private ReadOnly _connectionString As String
    Private ReadOnly _de As CultureInfo = CultureInfo.GetCultureInfo("de-DE")

    Public Sub New(connectionString As String)
        _connectionString = connectionString
    End Sub

    ' Mehrere Dateien importieren
    Public Sub ImportFiles(filePaths As IEnumerable(Of String))
        For Each p In filePaths
            ImportSingleFile(p)
        Next
    End Sub

    Private Sub ImportSingleFile(filePath As String)
        Using wb As New XLWorkbook(filePath)
            Dim ws = wb.Worksheets.First()

            ' Header (Zeile 1) normalisieren
            Dim lastCol = ws.Row(1).LastCellUsed().Address.ColumnNumber
            Dim headers As New List(Of String)
            For c = 1 To lastCol
                headers.Add(NormalizeHeader(ws.Cell(1, c).GetString()))
            Next

            Dim layout = DetectLayout(headers)

            Select Case layout
                Case LayoutType.Exports
                    Dim dt = CreateExportsDataTable() ' Spaltennamen = SQL-Spalten EN
                    FillDataTable(ws, headers, dt, isExport:=True, sourceFile:=filePath)
                    BulkInsert(dt, "dbo.Customs_Exports")

                Case LayoutType.Imports
                    Dim dt = CreateImportsDataTable()
                    FillDataTable(ws, headers, dt, isExport:=False, sourceFile:=filePath)
                    BulkInsert(dt, "dbo.Customs_Imports")

                Case Else
                    Throw New InvalidOperationException($"Unknown layout in file: {filePath}")
            End Select
        End Using
    End Sub

    Private Enum LayoutType
        Unknown = 0
        Exports = 1
        [Imports] = 2
    End Enum

    Private Function DetectLayout(headers As List(Of String)) As LayoutType
        ' Export: hat "tcgb statü açıklaması" ODER "gümrük istatistik tarihi"
        If headers.Any(Function(h) h.Contains("tcgb statu aciklamasi") OrElse h.Contains("gumruk istatistik tarihi")) Then
            Return LayoutType.Exports
        End If
        ' Import: hat "gümrük idaresi kodu" und "tcgb kapanış tarihi"
        If headers.Any(Function(h) h.Contains("gumruk idaresi kodu")) AndAlso
           headers.Any(Function(h) h.Contains("tcgb kapanis tarihi")) Then
            Return LayoutType.Imports
        End If
        Return LayoutType.Unknown
    End Function

    Private Function NormalizeHeader(raw As String) As String
        If raw Is Nothing Then Return ""
        Dim s = raw.Trim().ToLowerInvariant()
        s = s.Replace("ı", "i").Replace("ş", "s").Replace("ğ", "g").Replace("ü", "u").Replace("ö", "o").Replace("ç", "c")
        s = System.Text.RegularExpressions.Regex.Replace(s, "\s+", " ")
        Return s
    End Function

    ' --- DataTables: Spaltennamen = EN-Tabellenschema ---
    Private Function CreateExportsDataTable() As DataTable
        Dim dt As New DataTable("Customs_Exports")
        dt.Columns.Add("CustomsOfficeName", GetType(String))
        dt.Columns.Add("RegistrationNo", GetType(String))
        dt.Columns.Add("RegistrationDate", GetType(Date))
        dt.Columns.Add("StatisticsDate", GetType(Date))
        dt.Columns.Add("ConsignorConsigneeTaxNo", GetType(String))
        dt.Columns.Add("ConsignorConsigneeName", GetType(String))
        dt.Columns.Add("ConsigneeName", GetType(String))
        dt.Columns.Add("DestinationCountryCode", GetType(String))
        dt.Columns.Add("DestinationCountryName", GetType(String))
        dt.Columns.Add("OriginCountryCode", GetType(String))
        dt.Columns.Add("OriginCountryName", GetType(String))
        dt.Columns.Add("IncotermCode", GetType(String))
        dt.Columns.Add("LineNo", GetType(Integer))
        dt.Columns.Add("RegimeCode", GetType(String))
        dt.Columns.Add("RegimeDescription", GetType(String))
        dt.Columns.Add("HSCode", GetType(String))
        dt.Columns.Add("HSDescription", GetType(String))
        dt.Columns.Add("CommercialDescription", GetType(String))
        dt.Columns.Add("DeclarationStatus", GetType(String))
        dt.Columns.Add("InvoiceAmount", GetType(Decimal))
        dt.Columns.Add("InvoiceCurrencyCode", GetType(String))
        dt.Columns.Add("Quantity", GetType(Decimal))
        dt.Columns.Add("QuantityUnit", GetType(String))
        dt.Columns.Add("NetWeightKg", GetType(Decimal))
        dt.Columns.Add("CalculatedLineValueUSD", GetType(Decimal))
        dt.Columns.Add("StatisticalValueUSD", GetType(Decimal))
        dt.Columns.Add("SourceFile", GetType(String))
        dt.Columns.Add("ImportedAtUtc", GetType(DateTime))
        Return dt
    End Function

    Private Function CreateImportsDataTable() As DataTable
        Dim dt As New DataTable("Customs_Imports")
        dt.Columns.Add("CustomsOfficeCode", GetType(String))
        dt.Columns.Add("CustomsOfficeName", GetType(String))
        dt.Columns.Add("RegistrationNo", GetType(String))
        dt.Columns.Add("RegistrationDate", GetType(Date))
        dt.Columns.Add("ClosingDate", GetType(Date))
        dt.Columns.Add("ConsignorConsigneeTaxNo", GetType(String))
        dt.Columns.Add("ConsignorConsigneeName", GetType(String))
        dt.Columns.Add("SenderName", GetType(String))
        dt.Columns.Add("DispatchCountryCode", GetType(String))
        dt.Columns.Add("DispatchCountryName", GetType(String))
        dt.Columns.Add("OriginCountryCode", GetType(String))
        dt.Columns.Add("OriginCountryName", GetType(String))
        dt.Columns.Add("IncotermCode", GetType(String))
        dt.Columns.Add("LineNo", GetType(Integer))
        dt.Columns.Add("RegimeCode", GetType(String))
        dt.Columns.Add("RegimeDescription", GetType(String))
        dt.Columns.Add("HSCode", GetType(String))
        dt.Columns.Add("HSDescription", GetType(String))
        dt.Columns.Add("CommercialDescription", GetType(String))
        dt.Columns.Add("InvoiceAmount", GetType(Decimal))
        dt.Columns.Add("InvoiceCurrencyCode", GetType(String))
        dt.Columns.Add("Quantity", GetType(Decimal))
        dt.Columns.Add("QuantityUnit", GetType(String))
        dt.Columns.Add("NetWeightKg", GetType(Decimal))
        dt.Columns.Add("CalculatedLineValueUSD", GetType(Decimal))
        dt.Columns.Add("StatisticalValueUSD", GetType(Decimal))
        dt.Columns.Add("SourceFile", GetType(String))
        dt.Columns.Add("ImportedAtUtc", GetType(DateTime))
        Return dt
    End Function

    ' --- Excel -> DataTable ---
    Private Sub FillDataTable(ws As IXLWorksheet,
                              headers As List(Of String),
                              dt As DataTable,
                              isExport As Boolean,
                              sourceFile As String)

        Dim rowFirst = 2
        Dim rowLast = ws.LastRowUsed().RowNumber()
        Dim colLast = ws.Row(1).LastCellUsed().Address.ColumnNumber

        Dim map As Dictionary(Of String, String) =
            If(isExport, GetExportHeaderMap(), GetImportHeaderMap())

        For r = rowFirst To rowLast
            Dim dr = dt.NewRow()
            dr("SourceFile") = sourceFile
            dr("ImportedAtUtc") = DateTime.UtcNow

            For c = 1 To colLast
                Dim rawHeader = NormalizeHeader(ws.Cell(1, c).GetString())
                If Not map.ContainsKey(rawHeader) Then Continue For

                Dim targetCol = map(rawHeader)
                Dim txt = ws.Cell(r, c).GetFormattedString().Trim()

                If String.IsNullOrWhiteSpace(txt) Then
                    ' skip
                ElseIf dt.Columns(targetCol).DataType Is GetType(Date) Then
                    dr(targetCol) = ParseDate(txt)
                ElseIf dt.Columns(targetCol).DataType Is GetType(Decimal) Then
                    dr(targetCol) = ParseDecimal(txt)
                ElseIf dt.Columns(targetCol).DataType Is GetType(Integer) Then
                    Dim i As Integer
                    If Integer.TryParse(txt, NumberStyles.Any, _de, i) OrElse
                       Integer.TryParse(txt, NumberStyles.Any, CultureInfo.InvariantCulture, i) Then
                        dr(targetCol) = i
                    End If
                Else
                    dr(targetCol) = txt
                End If
            Next

            ' Mindestprüfung: RegistrationNo muss da sein
            If dt.Columns.Contains("RegistrationNo") AndAlso
               Not IsDBNull(dr("RegistrationNo")) AndAlso
               Not String.IsNullOrWhiteSpace(CStr(dr("RegistrationNo"))) Then
                dt.Rows.Add(dr)
            End If
        Next
    End Sub

    Private Function ParseDecimal(s As String) As Decimal
        Dim d As Decimal
        If Decimal.TryParse(s, NumberStyles.Any, _de, d) Then Return d         ' 3.499,09
        If Decimal.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, d) Then Return d ' 3499.09
        Return 0D
    End Function

    Private Function ParseDate(s As String) As Date
        Dim d As Date
        Dim formats = {
            "dd.MMM.yyyy", "d.MMM.yyyy",
            "dd.MM.yyyy", "d.MM.yyyy",
            "dd.MMM.yy", "dd.MM.yy",
            "yyyy-MM-dd", "dd-MMM-yyyy"
        }
        If Date.TryParseExact(s, formats, _de, DateTimeStyles.None, d) Then Return d
        If Date.TryParse(s, _de, DateTimeStyles.None, d) Then Return d
        If Date.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.None, d) Then Return d
        Return Date.MinValue
    End Function

    Private Sub BulkInsert(dt As DataTable, targetTable As String)
        Using cn As New SqlConnection(_connectionString)
            cn.Open()
            Using bulk As New SqlBulkCopy(cn)
                bulk.DestinationTableName = targetTable
                bulk.BulkCopyTimeout = 0
                bulk.BatchSize = 10000
                For Each col As DataColumn In dt.Columns
                    bulk.ColumnMappings.Add(col.ColumnName, col.ColumnName)
                Next
                bulk.WriteToServer(dt)
            End Using
        End Using
    End Sub

    ' --- Header-Mappings: Türkischer Exceltitel -> EN-Spalte ---
    Private Function GetExportHeaderMap() As Dictionary(Of String, String)
        Return New Dictionary(Of String, String) From {
            {"tcgb", "CustomsOfficeName"},
            {"gümrük idaresi adı", "CustomsOfficeName"}, ' manche Dateien haben beide
            {"tcgb tescil no", "RegistrationNo"},
            {"tcgb tescil tarihi", "RegistrationDate"},
            {"gümrük istatistik tarihi (bordro tarihi)", "StatisticsDate"},
            {"gonderici / alici vergi no", "ConsignorConsigneeTaxNo"},
            {"gonderici/alici adi", "ConsignorConsigneeName"},
            {"alici adi", "ConsigneeName"},
            {"gidecegi ulke (17) kodu", "DestinationCountryCode"},
            {"gidecegi ulke (17) adi", "DestinationCountryName"},
            {"mense ulke kodu", "OriginCountryCode"},
            {"mense ulke adi", "OriginCountryName"},
            {"teslim sekli kodu", "IncotermCode"},
            {"kalem sira no", "LineNo"},
            {"kalem rejim kodu", "RegimeCode"},
            {"kalem rejim aciklamasi", "RegimeDescription"},
            {"gtip kodu", "HSCode"},
            {"gtip aciklamasi", "HSDescription"},
            {"31. ticari tanimi", "CommercialDescription"},
            {"tcgb statu aciklamasi", "DeclarationStatus"},
            {"fatura tutari", "InvoiceAmount"},
            {"fatura tutari doviz turu kodu", "InvoiceCurrencyCode"},
            {"olcu (esya) miktari", "Quantity"},
            {"olcu birimi aciklamasi", "QuantityUnit"},
            {"net agirlik (kg)", "NetWeightKg"},
            {"hesaplanmis kalem kiymeti usd degeri", "CalculatedLineValueUSD"},
            {"istatistiki kiymet usd degeri", "StatisticalValueUSD"}
        }
    End Function

    Private Function GetImportHeaderMap() As Dictionary(Of String, String)
        Return New Dictionary(Of String, String) From {
            {"gümrük idaresi kodu", "CustomsOfficeCode"},
            {"gumruk idaresi kodu", "CustomsOfficeCode"},
            {"gümrük idaresi adı", "CustomsOfficeName"},
            {"gumruk idaresi adi", "CustomsOfficeName"},
            {"tcgb tescil no", "RegistrationNo"},
            {"tcgb tescil tarihi", "RegistrationDate"},
            {"tcgb kapanis tarihi", "ClosingDate"},
            {"gonderici / alici vergi no", "ConsignorConsigneeTaxNo"},
            {"gonderici/alici adi", "ConsignorConsigneeName"},
            {"gonderen adi", "SenderName"},
            {"cikis ulkesi kodu", "DispatchCountryCode"},
            {"cikis ulkesi adi", "DispatchCountryName"},
            {"mense ulke kodu", "OriginCountryCode"},
            {"mense ulke adi", "OriginCountryName"},
            {"teslim sekli kodu", "IncotermCode"},
            {"kalem sira no", "LineNo"},
            {"kalem rejim kodu", "RegimeCode"},
            {"kalem rejim aciklamasi", "RegimeDescription"},
            {"gtip kodu", "HSCode"},
            {"gtip aciklamasi", "HSDescription"},
            {"31. ticari tanimi", "CommercialDescription"},
            {"fatura tutari", "InvoiceAmount"},
            {"fatura doviz kodu", "InvoiceCurrencyCode"},
            {"olcu (esya) miktari", "Quantity"},
            {"olcu birimi aciklamasi", "QuantityUnit"},
            {"net agirlik (kg)", "NetWeightKg"},
            {"hesaplanmis kalem kiymeti usd degeri", "CalculatedLineValueUSD"},
            {"istatistiki kiymet usd degeri", "StatisticalValueUSD"}
        }
    End Function

End Class