local D=script:FindFirstAncestor("\084\101\120\116\069\100\105\116\111\114")local o=game:GetService("\067\104\097\110\103\101\072\105\115\116\111\114\121\083\101\114\118\105\099\101")local m=require(D.Packages.Roact)local c=require(D.Packages.RoactRodux)local f=require(D.Packages.Llama)local R=require(D.Packages.Maid)local K=m.Component:extend("\084\101\120\116\069\100\105\116\111\114")local C=require(script.Parent.Toolbar)local B=require(script.Parent.Section)local t=require(script.Parent.TextLabel)local n=require(script.Parent.TextBox)function K.init(D)D.textItemMaid=R.new()D.inputRef=m.createRef()D.selectionStartPosition,D.updateSelectionStartPosition=m.createBinding(-1)D.cursorPosition,D.updateCursorPosition=m.createBinding(-1)end function K._saveText(D)local m=D.props.labelText:getValue()if D.props.TextItem.Text~=m then D.props.TextItem.Text=m o:SetWaypoint("\085\112\100\097\116\101\100 \116\101\120\116")end end function K._addTextItemConnections(D)D.textItemMaid:DoCleaning()D.textItemMaid:GiveTask((D.props.TextItem:GetPropertyChangedSignal("\084\101\120\116")):Connect(function()local o=D.inputRef:getValue()if o then o.Text=D.props.TextItem.Text end end))D.textItemMaid:GiveTask((D.props.TextItem:GetPropertyChangedSignal("\084\101\120\116\088\065\108\105\103\110\109\101\110\116")):Connect(function()if D.props.TextXAlignment~=D.props.TextItem.TextXAlignment then D.props.setXAlignment(D.props.TextItem.TextXAlignment)end end))D.textItemMaid:GiveTask((D.props.TextItem:GetPropertyChangedSignal("\070\111\110\116")):Connect(function()if D.props.Font~=D.props.TextItem.Font then D.props.setFont(D.props.TextItem.Font)end end))D.textItemMaid:GiveTask((D.props.TextItem:GetPropertyChangedSignal("\084\101\120\116\083\105\122\101")):Connect(function()if D.props.TextSize~=D.props.TextItem.TextSize then D.props.setTextSize(D.props.TextItem.TextSize)end end))end function K.didMount(D)D:_addTextItemConnections()end function K.didUpdate(m,D,o)if D.TextItem~=m.props.TextItem then m:_addTextItemConnections()end end function K.willUnmount(D)D.textItemMaid:DoCleaning()end function K.render(D)return m.createFragment({Padding=m.createElement("\085\073\080\097\100\100\105\110\103",{PaddingLeft=UDim.new(0,5);PaddingRight=UDim.new(0,5);PaddingTop=UDim.new(0,5);PaddingBottom=UDim.new(0,5)}),Layout=m.createElement("\085\073\076\105\115\116\076\097\121\111\117\116",{Padding=UDim.new(0,5);SortOrder=Enum.SortOrder.LayoutOrder,[m.Change.AbsoluteContentSize]=function(o)D.props.updateHolderSize(o.AbsoluteContentSize.Y+10)end}),Toolbar=m.createElement(C,{inputRef=D.inputRef,cursorPosition=D.cursorPosition,selectionStartPosition=D.selectionStartPosition});TextBox=m.createElement(n,{[m.Ref]=D.inputRef;LayoutOrder=2;Text=D.props.TextItem.Text,ClearTextOnFocus=false;MultiLine=true,Width=UDim.new(1,0),BackgroundTransparency=0,[m.Change.Text]=function(o)D.props.updateLabelText(o.Text)end,[m.Change.SelectionStart]=function(o)(coroutine.wrap(function()wait(.3)D.updateSelectionStartPosition(o.SelectionStart)end))()end,[m.Change.CursorPosition]=function(o)(coroutine.wrap(function()wait(.3)D.updateCursorPosition(o.CursorPosition)end))()end;[m.Event.FocusLost]=function()D:_saveText()end},{SizeConstraint=m.createElement("\085\073\083\105\122\101\067\111\110\115\116\114\097\105\110\116",{MinSize=Vector2.new(0,100)})});Output=m.createElement(B,{LayoutOrder=3;Title="\079\117\116\112\117\116"},{Padding=m.createElement("\085\073\080\097\100\100\105\110\103",{PaddingTop=UDim.new(0,5),PaddingBottom=UDim.new(0,5)});OutputLabel=m.createElement(t,{BackgroundTransparency=1,Text=D.props.labelText;RichText=true,Width=UDim.new(1,0);Font=D.props.Font,TextColor3=D.props.TextItem.TextColor3;TextSize=D.props.TextSize,TextStrokeColor3=D.props.TextItem.TextStrokeColor3;TextStrokeTransparency=D.props.TextItem.TextStrokeTransparency,TextTransparency=D.props.TextItem.TextTransparency,TextXAlignment=D.props.TextXAlignment})})})end return(c.connect(function(D,o)if D.TextItem~=o.TextItem then local m=f.Dictionary.copy(o)m.TextItem=D.TextItem m.TextXAlignment=D.TextXAlignment m.Font=D.Font m.TextSize=D.TextSize return m end return o end,function(D)return{setXAlignment=function(o)D({type="\115\101\116\088\065\108\105\103\110\109\101\110\116";alignment=o})end;setFont=function(o)D({type="\115\101\116\070\111\110\116",font=o})end;setTextSize=function(o)D({type="\115\101\116\084\101\120\116\083\105\122\101";textSize=o})end}end))(K)
local TextEditor = script:FindFirstAncestor("TextEditor")
local ChangeHistoryService = game:GetService("ChangeHistoryService")
local Roact = require(TextEditor.Packages.Roact)
local RoactRodux = require(TextEditor.Packages.RoactRodux)
local Llama = require(TextEditor.Packages.Llama)
local Maid = require(TextEditor.Packages.Maid)

local TextEditorComponent = Roact.Component:extend("TextEditor")
local Toolbar = require(script.Parent.Toolbar)
local Section = require(script.Parent.Section)
local ThemedTextLabel = require(script.Parent.TextLabel)
local ThemedTextBox = require(script.Parent.TextBox)

-- local KEYCODES_FOR_TAGS = {
--   [Enum.KeyCode.B] = "b",
--   [Enum.KeyCode.I] = "i",
--   [Enum.KeyCode.U] = "u",
-- }

function TextEditorComponent:init()
  self.textItemMaid = Maid.new() -- Maid related to the TextItem involved

  self.inputRef = Roact.createRef()
  self.selectionStartPosition, self.updateSelectionStartPosition = Roact.createBinding(-1) -- This is a delayed value as the textbox loses focus before a Button Activated event occurs
  self.cursorPosition, self.updateCursorPosition = Roact.createBinding(-1) -- Same as above
end

function TextEditorComponent:_saveText()
  local newText = self.props.labelText:getValue()

  if self.props.TextItem.Text ~= newText then
    self.props.TextItem.Text = newText
    ChangeHistoryService:SetWaypoint("Updated text")
  end
end

function TextEditorComponent:_addTextItemConnections()
  self.textItemMaid:DoCleaning() -- Clear any old connections

  -- Connect to any property changes of the TextItem, so that the Text Editor is up to date
  self.textItemMaid:GiveTask(self.props.TextItem:GetPropertyChangedSignal("Text"):Connect(function()
    local textBox = self.inputRef:getValue()
    if textBox then
      textBox.Text = self.props.TextItem.Text
    end
  end))

  self.textItemMaid:GiveTask(self.props.TextItem:GetPropertyChangedSignal("TextXAlignment"):Connect(function()
    if self.props.TextXAlignment ~= self.props.TextItem.TextXAlignment then
      self.props.setXAlignment(self.props.TextItem.TextXAlignment)
    end
  end))

  self.textItemMaid:GiveTask(self.props.TextItem:GetPropertyChangedSignal("Font"):Connect(function()
    if self.props.Font ~= self.props.TextItem.Font then
      self.props.setFont(self.props.TextItem.Font)
    end
  end))

  self.textItemMaid:GiveTask(self.props.TextItem:GetPropertyChangedSignal("TextSize"):Connect(function()
    if self.props.TextSize ~= self.props.TextItem.TextSize then
      self.props.setTextSize(self.props.TextItem.TextSize)
    end
  end))
end

function TextEditorComponent:didMount()
  self:_addTextItemConnections()
end

function TextEditorComponent:didUpdate(prevProps, _prevState)
  if prevProps.TextItem ~= self.props.TextItem then
    self:_addTextItemConnections()
  end
end

function TextEditorComponent:willUnmount()
  self.textItemMaid:DoCleaning()
end

-- function TextEditorComponent:didMount()
--   local overlay = self.props.overlayRef:getValue()
--   local textBox = self.inputRef:getValue()
--   TODO: Keybinds
--   self.maid:GiveTask(overlay.InputBegan:Connect(function(InputObject)
--     if InputObject:IsModifierKeyDown(Enum.ModifierKey.Ctrl) then
--       if KEYCODES_FOR_TAGS[InputObject.KeyCode] then
--         textBox.Text = addTagsAroundSelection(textBox, textBox.CursorPosition, textBox.SelectionStart, KEYCODES_FOR_TAGS[InputObject.KeyCode])
--       end
--     end
--   end))

--   See main.server.lua for reason this is not used
--   self.maid:GiveTask(self.props.pluginActions.toggleBold.Triggered:Connect(self:toggleTagWrapper("b")))
--   self.maid:GiveTask(self.props.pluginActions.toggleItalic.Triggered:Connect(self:toggleTagWrapper("i")))
--   self.maid:GiveTask(self.props.pluginActions.toggleUnderline.Triggered:Connect(self:toggleTagWrapper("u")))
--   self.maid:GiveTask(self.props.pluginActions.toggleStrikethrough.Triggered:Connect(self:toggleTagWrapper("s")))
-- end

function TextEditorComponent:render()
  return Roact.createFragment({
    Padding = Roact.createElement("UIPadding", {
      PaddingLeft = UDim.new(0, 5),
      PaddingRight = UDim.new(0, 5),
      PaddingTop = UDim.new(0, 5),
      PaddingBottom = UDim.new(0, 5),
    }),
  
    Layout = Roact.createElement("UIListLayout", {
      Padding = UDim.new(0, 5),
      SortOrder = Enum.SortOrder.LayoutOrder,
      [Roact.Change.AbsoluteContentSize] = function(rbx)
        self.props.updateHolderSize(rbx.AbsoluteContentSize.Y + 10) -- Addition due to padding
      end,
    }),
  
    Toolbar = Roact.createElement(Toolbar, {
      inputRef = self.inputRef,
      cursorPosition = self.cursorPosition,
      selectionStartPosition = self.selectionStartPosition,
    }),
  
    TextBox = Roact.createElement(ThemedTextBox, {
      [Roact.Ref] = self.inputRef,
      LayoutOrder = 2,
      Text = self.props.TextItem.Text,
      ClearTextOnFocus = false,
      MultiLine = true,
      Width = UDim.new(1, 0),
      BackgroundTransparency = 0,
  
      [Roact.Change.Text] = function(rbx)
        self.props.updateLabelText(rbx.Text)
      end,
  
      [Roact.Change.SelectionStart] = function(rbx)
        coroutine.wrap(function()
          wait(0.3)
          self.updateSelectionStartPosition(rbx.SelectionStart)
        end)()
      end,
  
      [Roact.Change.CursorPosition] = function(rbx)
        coroutine.wrap(function()
          wait(0.3)
          self.updateCursorPosition(rbx.CursorPosition)
        end)()
      end,

      [Roact.Event.FocusLost] = function()
        self:_saveText()
      end,
    }, {
      SizeConstraint = Roact.createElement("UISizeConstraint", {
        MinSize = Vector2.new(0, 100),
      }),
    }),
  
    Output = Roact.createElement(Section, {
      LayoutOrder = 3,
      Title = "Output",
    }, {
      Padding = Roact.createElement("UIPadding", {
        PaddingTop = UDim.new(0, 5),
        PaddingBottom = UDim.new(0, 5),
      }),
  
      OutputLabel = Roact.createElement(ThemedTextLabel, {
        BackgroundTransparency = 1,
        Text = self.props.labelText,
        RichText = true,
        Width = UDim.new(1, 0),
        
        -- Copy the label text
        Font = self.props.Font, -- This is specifically managed in the Rodux store
        TextColor3 = self.props.TextItem.TextColor3,
        TextSize = self.props.TextSize, -- This is specifically managed in the Rodux store
        TextStrokeColor3 = self.props.TextItem.TextStrokeColor3,
        TextStrokeTransparency = self.props.TextItem.TextStrokeTransparency,
        TextTransparency = self.props.TextItem.TextTransparency,
        TextXAlignment = self.props.TextXAlignment, -- This is specifically managed in the Rodux store
      })
    }),
  })
end

return RoactRodux.connect(
  function(state, props)
    if state.TextItem ~= props.TextItem then
      local newProps = Llama.Dictionary.copy(props)
      newProps.TextItem = state.TextItem
      newProps.TextXAlignment = state.TextXAlignment
      newProps.Font = state.Font
      newProps.TextSize = state.TextSize
      return newProps
    end
    return props
  end,
  function(dispatch)
    return {
      setXAlignment = function(alignment)
        dispatch({ type = "setXAlignment", alignment = alignment })
      end,
      setFont = function(font)
        dispatch({ type = "setFont", font = font })
      end,
      setTextSize = function(textSize)
        dispatch({ type = "setTextSize", textSize = textSize })
      end,
    }
  end
)(TextEditorComponent)