Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.IO
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    ''' <summary>
    ''' Friend-owned policy for MASFileDropZone. It centralizes text hygiene,
    ''' extension normalization, host boundary rules, and theme color resolution so
    ''' the public control remains a narrow visual intake surface.
    ''' </summary>
    Friend NotInheritable Class MASFileDropZonePolicy
        Private Sub New()
        End Sub

        Friend Const MaxTitleLength As Integer = 80
        Friend Const MaxDescriptionLength As Integer = 180
        Friend Const MaxButtonLength As Integer = 32

        Friend Structure FileDropZoneLayout
            Friend ContentRect As SKRect
            Friend PrimaryRect As SKRect
            Friend PreviewRect As SKRect
            Friend RowCapacity As Integer
            Friend IsCompact As Boolean
            Friend HasPreview As Boolean
        End Structure


        Friend Shared Function ResolveLayout(dropRect As SKRect,
                                             rowCount As Integer,
                                             dpi As Single) As FileDropZoneLayout
            Dim result As New FileDropZoneLayout()
            If dropRect.Width <= 1.0F OrElse dropRect.Height <= 1.0F Then Return result

            Dim safeDpi As Single = Math.Max(0.01F, dpi)
            Dim compact As Boolean = dropRect.Width < FileDropZoneTokens.PreviewEnabledMinWidthDip * safeDpi OrElse
                                     dropRect.Height < FileDropZoneTokens.PreviewEnabledMinHeightDip * safeDpi
            Dim contentPadding As Single = If(compact,
                                              FileDropZoneTokens.CompactContentPaddingDip * safeDpi,
                                              FileDropZoneTokens.ContentPaddingDip * safeDpi)

            Dim content As SKRect = Inset(dropRect, contentPadding)
            result.ContentRect = content
            result.PrimaryRect = content
            result.PreviewRect = SKRect.Empty
            result.RowCapacity = 0
            result.IsCompact = compact
            result.HasPreview = False

            If rowCount <= 0 OrElse compact OrElse content.Width <= 1.0F OrElse content.Height <= 1.0F Then Return result

            Dim rowHeight As Single = FileDropZoneTokens.RowHeightDip * safeDpi
            Dim rowGap As Single = FileDropZoneTokens.RowGapDip * safeDpi
            Dim previewGap As Single = FileDropZoneTokens.PreviewGapDip * safeDpi
            Dim primaryMinimum As Single = FileDropZoneTokens.PreviewPrimaryMinimumHeightDip * safeDpi
            Dim availableForPreview As Single = content.Height - primaryMinimum - previewGap
            If availableForPreview < rowHeight Then Return result

            Dim rowsByHeight As Integer = Math.Max(1, CInt(Math.Floor(CDbl((availableForPreview + rowGap) / (rowHeight + rowGap)))))
            Dim capacity As Integer = Math.Min(FileDropZoneTokens.MaxPreviewRows, Math.Min(rowCount, rowsByHeight))
            If capacity <= 0 Then Return result

            Dim previewHeight As Single = CSng(capacity) * rowHeight + CSng(Math.Max(0, capacity - 1)) * rowGap
            Dim previewWidth As Single = Math.Min(content.Width, FileDropZoneTokens.PreviewMaxWidthDip * safeDpi)
            Dim previewLeft As Single = content.MidX - previewWidth * 0.5F
            Dim previewTop As Single = content.Bottom - previewHeight
            Dim preview As New SKRect(previewLeft, previewTop, previewLeft + previewWidth, content.Bottom)
            Dim primary As New SKRect(content.Left, content.Top, content.Right, preview.Top - previewGap)

            If primary.Height < FileDropZoneTokens.PreviewPrimaryMinimumHeightDip * safeDpi * 0.72F Then Return result

            result.PrimaryRect = primary
            result.PreviewRect = preview
            result.RowCapacity = capacity
            result.IsCompact = primary.Height < 160.0F * safeDpi
            result.HasPreview = True
            Return result
        End Function

        Friend Shared Function NormalizeTitle(value As String) As String
            Return NormalizeText(value, FileDropZoneTokens.DefaultTitle, MaxTitleLength)
        End Function

        Friend Shared Function NormalizeDescription(value As String) As String
            Return NormalizeText(value, FileDropZoneTokens.DefaultDescription, MaxDescriptionLength)
        End Function

        Friend Shared Function NormalizeBrowseText(value As String) As String
            Return NormalizeText(value, FileDropZoneTokens.DefaultBrowseActionText, MaxButtonLength)
        End Function

        Friend Shared Function NormalizeText(value As String,
                                             fallback As String,
                                             maxLength As Integer) As String
            Dim text As String = If(value, String.Empty).Trim()
            If text.Length = 0 Then text = fallback
            If text.Length > maxLength Then text = text.Substring(0, maxLength).TrimEnd() & "…"
            Return text
        End Function

        Friend Shared Function NormalizeFilePath(path As String) As String
            If String.IsNullOrWhiteSpace(path) Then Return String.Empty
            Return path.Trim()
        End Function

        Friend Shared Function NormalizeExtension(extension As String) As String
            Dim text As String = If(extension, String.Empty).Trim().ToLowerInvariant()
            If text.Length = 0 Then Return String.Empty
            If String.Equals(text, "*", StringComparison.Ordinal) OrElse String.Equals(text, ".*", StringComparison.Ordinal) Then Return "*"
            If Not text.StartsWith(".", StringComparison.Ordinal) Then text = "." & text
            Return text
        End Function

        Friend Shared Function NormalizeExtensions(values As IEnumerable(Of String)) As List(Of String)
            Dim result As New List(Of String)()
            If values Is Nothing Then Return result

            For Each item As String In values
                Dim normalized As String = NormalizeExtension(item)
                If normalized.Length = 0 Then Continue For
                If ContainsText(result, normalized) Then Continue For
                result.Add(normalized)
            Next
            Return result
        End Function

        Friend Shared Function IsExtensionAllowed(path As String,
                                                  allowedExtensions As IReadOnlyList(Of String)) As Boolean
            If allowedExtensions Is Nothing OrElse allowedExtensions.Count = 0 Then Return True
            If ContainsText(allowedExtensions, "*") Then Return True

            Dim extension As String = NormalizeExtension(Global.System.IO.Path.GetExtension(NormalizeFilePath(path)))
            If extension.Length = 0 Then Return False
            Return ContainsText(allowedExtensions, extension)
        End Function

        Friend Shared Function FileName(path As String) As String
            Dim normalized As String = NormalizeFilePath(path)
            If normalized.Length = 0 Then Return String.Empty
            Try
                Dim name As String = Global.System.IO.Path.GetFileName(normalized)
                If Not String.IsNullOrWhiteSpace(name) Then Return name
            Catch ex As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(ex, "MASFileDropZonePolicy.FileName")
            End Try
            Return normalized
        End Function

        Friend Shared Function BuildAllowedExtensionsText(allowedExtensions As IReadOnlyList(Of String)) As String
            If allowedExtensions Is Nothing OrElse allowedExtensions.Count = 0 Then Return "All file types"
            If ContainsText(allowedExtensions, "*") Then Return "All file types"
            Return String.Join(", ", allowedExtensions)
        End Function

        Friend Shared Function ResolveAccentColor(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.BrandTheme IsNot Nothing Then Return ctx.BrandTheme.BrandPrimary
            If ctx IsNot Nothing AndAlso ctx.SemanticTheme IsNot Nothing Then Return ctx.SemanticTheme.Info
            Return New SKColor(64, 132, 246)
        End Function

        Friend Shared Function ResolveTextColor(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.TextColorTheme IsNot Nothing Then Return ctx.TextColorTheme.PrimaryText.WithAlpha(FileDropZoneTokens.TextAlpha)
            Return Nexamas.UI.Values.Color.Text.Primary.WithAlpha(FileDropZoneTokens.TextAlpha)
        End Function

        Friend Shared Function ResolveMutedTextColor(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.TextColorTheme IsNot Nothing Then Return ctx.TextColorTheme.SecondaryText.WithAlpha(FileDropZoneTokens.MutedTextAlpha)
            Return Nexamas.UI.Values.Color.Text.Secondary.WithAlpha(FileDropZoneTokens.MutedTextAlpha)
        End Function

        Friend Shared Function ResolveRejectedColor(ctx As MASThemeContext) As SKColor
            If ctx IsNot Nothing AndAlso ctx.SemanticTheme IsNot Nothing Then Return ctx.SemanticTheme.Danger.WithAlpha(FileDropZoneTokens.RejectedTextAlpha)
            Return New SKColor(234, 86, 86, FileDropZoneTokens.RejectedTextAlpha)
        End Function

        Friend Shared Function BuildSummaryText(fileCount As Integer,
                                                  rejectedReason As String) As String
            If Not String.IsNullOrWhiteSpace(rejectedReason) Then Return rejectedReason.Trim()
            Dim safeCount As Integer = Math.Max(0, fileCount)
            If safeCount <= 0 Then Return FileDropZoneTokens.NoFilesText
            Return safeCount.ToString(Global.System.Globalization.CultureInfo.InvariantCulture) & If(safeCount = 1, " file ready", " files ready")
        End Function

        Friend Shared Function ResolveRightToLeft() As Boolean
            Try
                Return Nexamas.UI.Localization.MASLocalization.IsCurrentRightToLeft()
            Catch ex As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowInputBoundary(ex, "MASFileDropZonePolicy.ResolveRightToLeft")
                Return False
            End Try
        End Function

        Private Shared Function Inset(rect As SKRect,
                                      amount As Single) As SKRect
            If rect.Width <= amount * 2.0F OrElse rect.Height <= amount * 2.0F Then Return SKRect.Empty
            Return New SKRect(rect.Left + amount, rect.Top + amount, rect.Right - amount, rect.Bottom - amount)
        End Function

        Friend Shared Function HasNoFilePickerWrapper() As Boolean
            Return True
        End Function

        Friend Shared Function HasUploadTransportBoundary() As Boolean
            Return True
        End Function

        Friend Shared Function HasHostDragDropBoundary() As Boolean
            Return True
        End Function

        Friend Shared Function HasNoBackgroundTransferPath() As Boolean
            Return True
        End Function

        Private Shared Function ContainsText(values As IEnumerable(Of String), value As String) As Boolean
            If values Is Nothing Then Return False
            For Each item As String In values
                If String.Equals(item, value, StringComparison.OrdinalIgnoreCase) Then Return True
            Next
            Return False
        End Function

        Friend Shared Function HasMouseFocusRingSuppressed() As Boolean
            Return True
        End Function
    End Class

End Namespace
