Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Windows.Forms
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Composition
Imports Nexamas.UI.Controls
Imports Nexamas.UI.General
Imports Nexamas.UI.Icons
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.TextRendering
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    ''' <summary>
    ''' Official Nexamas UI premium file intake drop-zone. It owns the visual selection
    ''' surface, accepted-file list, extension validation, browse intent event, keyboard
    ''' activation, and readiness evidence. OS drag/drop plumbing, FilePicker dialogs,
    ''' upload transport, storage, scanning, thumbnails, and background transfer remain
    ''' owned by the host application or existing Nexamas UI systems.
    ''' </summary>
    Partial Public NotInheritable Class MASFileDropZone
        Inherits MASControlBase
        Implements IMASLayoutParticipant
        Implements IMASIntrinsicSizeContract

#Region "Fields"

        Private Shared ReadOnly _contract As MASResolvedComponentContract =
            MASArchitectureRuntime.ResolveContractOrThrow(GetType(MASFileDropZone))

        Private Structure FileDropRow
            Friend Sub New(path As String, accepted As Boolean, reason As String)
                Me.Path = path
                Me.Accepted = accepted
                Me.Reason = If(reason, String.Empty)
            End Sub

            Friend Path As String
            Friend Accepted As Boolean
            Friend Reason As String
        End Structure

        Private NotInheritable Class FileDropRowHit
            Friend Sub New(fileIndex As Integer,
                           rowRect As SKRect,
                           closeRect As SKRect)
                Me.FileIndex = fileIndex
                Me.RowRect = rowRect
                Me.CloseRect = closeRect
            End Sub

            Friend ReadOnly Property FileIndex As Integer
            Friend ReadOnly Property RowRect As SKRect
            Friend ReadOnly Property CloseRect As SKRect
        End Class

        Private ReadOnly _primitives As New MASVisualPrimitivesPainter()
        Private ReadOnly _acceptedPaths As New List(Of String)()
        Private ReadOnly _rows As New List(Of FileDropRow)()
        Private ReadOnly _rowHits As New List(Of FileDropRowHit)()
        Private ReadOnly _allowedExtensions As New List(Of String)()
        Private _title As String = FileDropZoneTokens.DefaultTitle
        Private _description As String = FileDropZoneTokens.DefaultDescription
        Private _browseActionText As String = FileDropZoneTokens.DefaultBrowseActionText
        Private _multipleSelection As Boolean = True
        Private _lastRejectedReason As String = String.Empty
        Private _hoverBrowse As Boolean
        Private _pressedBrowse As Boolean
        Private _hoverRemoveIndex As Integer = -1
        Private _pressedRemoveIndex As Integer = -1
        Private _browseRect As SKRect = SKRect.Empty
        Private _dropRect As SKRect = SKRect.Empty

#End Region

#Region "Constructor / Factory"

        Public Sub New()
            MyBase.New()
        End Sub

        Public Shared Function Create(Optional title As String = Nothing,
                                      Optional description As String = Nothing) As MASFileDropZone
            Dim control As New MASFileDropZone()
            control._title = MASFileDropZonePolicy.NormalizeTitle(title)
            control._description = MASFileDropZonePolicy.NormalizeDescription(description)
            Return control
        End Function

#End Region

#Region "Public API"

        Public Event BrowseRequested As EventHandler
        Public Event FilesChanged As EventHandler

        Public Property Title As String
            Get
                Return _title
            End Get
            Set(value As String)
                Dim normalized As String = MASFileDropZonePolicy.NormalizeTitle(value)
                If String.Equals(_title, normalized, StringComparison.Ordinal) Then Return
                _title = normalized
                RequestSizeLayoutRefreshForSizeAffectingChange("MASFileDropZone.Title")
                InvalidateVisual()
            End Set
        End Property

        Public Property Description As String
            Get
                Return _description
            End Get
            Set(value As String)
                Dim normalized As String = MASFileDropZonePolicy.NormalizeDescription(value)
                If String.Equals(_description, normalized, StringComparison.Ordinal) Then Return
                _description = normalized
                RequestSizeLayoutRefreshForSizeAffectingChange("MASFileDropZone.Description")
                InvalidateVisual()
            End Set
        End Property

        Public Property BrowseActionText As String
            Get
                Return _browseActionText
            End Get
            Set(value As String)
                Dim normalized As String = MASFileDropZonePolicy.NormalizeBrowseText(value)
                If String.Equals(_browseActionText, normalized, StringComparison.Ordinal) Then Return
                _browseActionText = normalized
                RequestSizeLayoutRefreshForSizeAffectingChange("MASFileDropZone.BrowseActionText")
                InvalidateVisual()
            End Set
        End Property

        Public Property MultipleSelection As Boolean
            Get
                Return _multipleSelection
            End Get
            Set(value As Boolean)
                If _multipleSelection = value Then Return
                _multipleSelection = value
                If Not value AndAlso _acceptedPaths.Count > 1 Then
                    Dim first As String = _acceptedPaths(0)
                    _acceptedPaths.Clear()
                    _acceptedPaths.Add(first)
                    _rows.Clear()
                    _rowHits.Clear()
                    _rows.Add(New FileDropRow(first, True, String.Empty))
                    _hoverRemoveIndex = -1
                    _pressedRemoveIndex = -1
                    RaiseFilesChangedSafe()
                End If
                InvalidateVisual()
            End Set
        End Property

        Public ReadOnly Property AcceptedFiles As IReadOnlyList(Of String)
            Get
                Return New ReadOnlyCollection(Of String)(_acceptedPaths)
            End Get
        End Property

        Public ReadOnly Property FileCount As Integer
            Get
                Return _acceptedPaths.Count
            End Get
        End Property

        Public ReadOnly Property RejectedFileCount As Integer
            Get
                Dim count As Integer = 0
                For Each row As FileDropRow In _rows
                    If Not row.Accepted Then count += 1
                Next
                Return count
            End Get
        End Property

        Public ReadOnly Property LastRejectedReason As String
            Get
                Return _lastRejectedReason
            End Get
        End Property

        Public ReadOnly Property AllowedExtensionsText As String
            Get
                Return MASFileDropZonePolicy.BuildAllowedExtensionsText(_allowedExtensions)
            End Get
        End Property

        Public Function SetAllowedExtensions(ParamArray extensions As String()) As MASFileDropZone
            _allowedExtensions.Clear()
            _allowedExtensions.AddRange(MASFileDropZonePolicy.NormalizeExtensions(extensions))
            InvalidateVisual()
            Return Me
        End Function

        Public Function WithAllowedExtensions(ParamArray extensions As String()) As MASFileDropZone
            Return SetAllowedExtensions(extensions)
        End Function

        Public Function AcceptDroppedFile(path As String) As Boolean
            Return AcceptDroppedFiles(New String() {path}) > 0
        End Function

        Public Function AcceptDroppedFiles(paths As IEnumerable(Of String)) As Integer
            If paths Is Nothing Then Return 0
            Dim acceptedCount As Integer = 0
            For Each item As String In paths
                If TryAcceptFile(item) Then acceptedCount += 1
            Next

            If acceptedCount > 0 Then
                RaiseFilesChangedSafe()
                RequestSizeLayoutRefreshForSizeAffectingChange("MASFileDropZone.AcceptDroppedFiles")
            End If
            InvalidateVisual()
            Return acceptedCount
        End Function

        Public Function SetFiles(paths As IEnumerable(Of String)) As MASFileDropZone
            _acceptedPaths.Clear()
            _rows.Clear()
            _rowHits.Clear()
            _lastRejectedReason = String.Empty
            _hoverRemoveIndex = -1
            _pressedRemoveIndex = -1
            AcceptDroppedFiles(paths)
            Return Me
        End Function

        Public Function RemoveFileAt(index As Integer) As MASFileDropZone
            If index < 0 OrElse index >= _acceptedPaths.Count Then Return Me
            Dim removed As String = _acceptedPaths(index)
            _acceptedPaths.RemoveAt(index)
            _rows.RemoveAll(Function(row) row.Accepted AndAlso String.Equals(row.Path, removed, StringComparison.OrdinalIgnoreCase))
            _hoverRemoveIndex = -1
            _pressedRemoveIndex = -1
            RaiseFilesChangedSafe()
            RequestSizeLayoutRefreshForSizeAffectingChange("MASFileDropZone.RemoveFileAt")
            InvalidateVisual()
            Return Me
        End Function

        Public Function ClearFiles() As MASFileDropZone
            If _acceptedPaths.Count = 0 AndAlso _rows.Count = 0 Then Return Me
            _acceptedPaths.Clear()
            _rows.Clear()
            _rowHits.Clear()
            _lastRejectedReason = String.Empty
            _hoverRemoveIndex = -1
            _pressedRemoveIndex = -1
            RaiseFilesChangedSafe()
            RequestSizeLayoutRefreshForSizeAffectingChange("MASFileDropZone.ClearFiles")
            InvalidateVisual()
            Return Me
        End Function

        Public Function WithTitle(value As String) As MASFileDropZone
            Title = value
            Return Me
        End Function

        Public Function WithDescription(value As String) As MASFileDropZone
            Description = value
            Return Me
        End Function

        Public Function WithBrowseActionText(value As String) As MASFileDropZone
            BrowseActionText = value
            Return Me
        End Function

        Public Function WithMultipleSelection(value As Boolean) As MASFileDropZone
            MultipleSelection = value
            Return Me
        End Function

        Public Shadows Function WithSize(sizeIntent As MASSize) As MASFileDropZone
            MyBase.SetSize(sizeIntent)
            Return Me
        End Function

#End Region

    End Class

End Namespace
