-- UI/HelpPages/Profiles.lua
-- What Farm? :: HelpWindow - Profiles page (advanced profile management)
-- Keeps Settings page clean while exposing full profile tools in one place.

local ADDON_NAME, ns = ...
local WF = ns.WF

WF.UI = WF.UI or {}
WF.UI.HelpPages = WF.UI.HelpPages or {}

WF.UI.HelpPages.Profiles = function(ctx)
  local UI = ctx.UI
  local self = UI

  local WF = ctx.WF
  local Widgets = ctx.Widgets
  local Theme = ctx.Theme
  local Util = ctx.Util

  local Money = ctx.Money
  local Clamp = ctx.Clamp

  local MakePage = ctx.MakePage
  local MakePanel = ctx.MakePanel
  local MakeSectionTitle = ctx.MakeSectionTitle
  local MakeMutedText = ctx.MakeMutedText
  local MakeBodyText = ctx.MakeBodyText
  local MakeDivider = ctx.MakeDivider
  local MakeInput = ctx.MakeInput

  local C4 = ctx.C4
  local TEXT = ctx.TEXT
  local MUTED = ctx.MUTED
  local PANEL = ctx.PANEL
  local BORDER = ctx.BORDER

  local function SafeTrim(s)
    s = tostring(s or "")
    s = s:gsub("^%s+", ""):gsub("%s+$", "")
    return s
  end

  local function Lower(s)
    return tostring(s or ""):lower()
  end

  local function IsDefaultProfile(name)
    if WF and WF.DB and WF.DB.IsDefaultProfile then
      return WF.DB:IsDefaultProfile(name)
    end
    return false
  end

  local function GetActiveProfileName()
    if WF and WF.DB and WF.DB.GetActiveProfileName then
      return WF.DB:GetActiveProfileName()
    end
    return "Default"
  end

  local function GetProfileNames()
    if WF and WF.DB and WF.DB.GetProfileNames then
      return WF.DB:GetProfileNames()
    end
    return { "Default" }
  end


  local function DisplayProfileName(name)
    name = tostring(name or "")
    if name == "" then
      return "Default"
    end
    return name
  end

  local function GetProfile(name)
    if WF and WF.DB and WF.DB.GetProfile then
      return WF.DB:GetProfile(name)
    end
    return nil
  end

  local CATEGORY_META = {
    { key = "lootRecordMaterials", label = "Materials" },
    { key = "lootRecordGear", label = "Gear / Transmog" },
    { key = "lootRecordRecipes", label = "Recipes / Patterns" },
    { key = "lootRecordPets", label = "Pets" },
    { key = "lootRecordToys", label = "Toys" },
    { key = "lootRecordMounts", label = "Mounts" },
    { key = "lootRecordConsumables", label = "Consumables" },
    { key = "lootRecordMisc", label = "Misc / Other" },
  }

  local function HydrateCategorySelections(prof)
    if type(prof) ~= "table" then return end
    for i = 1, #CATEGORY_META do
      local key = CATEGORY_META[i].key
      prof[key] = prof[key] and true or false
    end

    local hasAny = false
    for i = 1, #CATEGORY_META do
      if prof[CATEGORY_META[i].key] then
        hasAny = true
        break
      end
    end
    if hasAny then return end

    local includeMaterials = prof.lootIncludeMaterials
    if includeMaterials == nil then includeMaterials = true end
    includeMaterials = includeMaterials and true or false

    if prof.lootOnlyMaterials then
      prof.lootRecordMaterials = true
      return
    end
    if prof.lootOnlyGear then
      prof.lootRecordGear = true
      return
    end
    if includeMaterials == false then
      prof.lootRecordGear = true
      prof.lootRecordRecipes = true
      prof.lootRecordPets = true
      prof.lootRecordToys = true
      prof.lootRecordMounts = true
      prof.lootRecordConsumables = true
      prof.lootRecordMisc = true
    end
  end

  local function CategorySummary(prof)
    if type(prof) ~= "table" then return "Everything" end
    HydrateCategorySelections(prof)
    local out = {}
    for i = 1, #CATEGORY_META do
      local meta = CATEGORY_META[i]
      if prof[meta.key] then
        out[#out + 1] = meta.label
      end
    end
    if #out == 0 then
      return "Everything"
    end
    if #out == (#CATEGORY_META - 1) and not prof.lootRecordMaterials then
      return "Everything except Materials"
    end
    return table.concat(out, ", ")
  end

  local function RefreshAfterProfileChange()
    -- Main window refreshes
    if WF and WF.UI and WF.UI.Main then
      local M = WF.UI.Main
      if M.RefreshProfileUI then M:RefreshProfileUI() end
      if M.RefreshTitle then M:RefreshTitle() end
      if M.RefreshMetrics then M:RefreshMetrics() end
      if M.RefreshLoot then M:RefreshLoot(true) end
    end

    -- Help window refreshes
    if UI and UI.RefreshLootSettings then UI:RefreshLootSettings() end
  end

  -- ---------------------------------------------------------
  -- Simple text prompt (modal) - scoped to HelpWindow
  -- ---------------------------------------------------------
  local function EnsureTextPrompt()
    if UI._wfTextPrompt then return end

    local blocker = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
    blocker:SetAllPoints(UIParent)
    blocker:EnableMouse(true)
    blocker:SetFrameStrata("DIALOG")
    blocker:SetBackdrop({ bgFile = "Interface/Buttons/WHITE8x8" })
    blocker:SetBackdropColor(0, 0, 0, 0.45)
    blocker:Hide()

    local box = CreateFrame("Frame", nil, blocker, "BackdropTemplate")
    box:SetSize(420, 180)
    box:SetPoint("CENTER", UIParent, "CENTER", 0, 40)
    box:SetBackdrop({
      bgFile = "Interface/Tooltips/UI-Tooltip-Background",
      edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
      edgeSize = 12,
      insets = { left = 3, right = 3, top = 3, bottom = 3 },
    })
    box:SetBackdropColor(C4(PANEL, PANEL))
    box:SetBackdropBorderColor(C4(BORDER, BORDER))

    local title = box:CreateFontString(nil, "OVERLAY", "WF_GameFontNormalLarge")
    title:SetPoint("TOPLEFT", 14, -12)
    title:SetTextColor(C4(TEXT, TEXT))
    title:SetText("Profile Name")

    local body = box:CreateFontString(nil, "OVERLAY", "WF_GameFontDisable")
    body:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -6)
    body:SetPoint("TOPRIGHT", box, "TOPRIGHT", -14, -40)
    body:SetTextColor(C4(MUTED, MUTED))
    body:SetJustifyH("LEFT")
    body:SetJustifyV("TOP")
    body:SetText("Enter a name:")

    local input = MakeInput(box, 392, 24)
    input:SetPoint("TOPLEFT", 14, -78)

    local bCancel = Widgets:Button(box, "Cancel", 92, 24)
    bCancel:SetPoint("BOTTOMRIGHT", -14, 12)

    local bOK = Widgets:Button(box, "OK", 92, 24)
    bOK:SetPoint("RIGHT", bCancel, "LEFT", -10, 0)

    local function Close()
      blocker:Hide()
      box:Hide()
      input:ClearFocus()
      input:SetText("")
      box._onOK = nil
    end

    blocker:SetScript("OnMouseDown", function()
      -- click outside closes, unless user is dragging selection
      Close()
    end)

    local function Commit()
      local cb = box._onOK
      if type(cb) ~= "function" then
        Close()
        return
      end

      local txt = SafeTrim(input:GetText())
      Close()
      cb(txt)
    end

    bCancel:SetScript("OnClick", Close)
    bOK:SetScript("OnClick", Commit)

    input:SetScript("OnEnterPressed", function()
      Commit()
    end)
    input:SetScript("OnEscapePressed", function()
      Close()
    end)

    UI._wfTextPrompt = {
      blocker = blocker,
      box = box,
      title = title,
      body = body,
      input = input,
      ok = bOK,
      cancel = bCancel,
      close = Close,
    }
  end

  local function PromptText(title, body, defaultText, okText, onOK)
    if Widgets and Widgets.OpenTextPrompt then
      Widgets:OpenTextPrompt(UI, "_wfTextPrompt", {
        title = title or "Profile Name",
        body = body or "Enter a name:",
        defaultText = defaultText or "",
        okText = okText or "OK",
        maxLetters = 64,
        onOK = onOK,
      })
      return
    end

    EnsureTextPrompt()
    local P = UI._wfTextPrompt

    P.title:SetText(title or "Profile Name")
    P.body:SetText(body or "Enter a name:")
    P.ok:SetText(okText or "OK")
    P.box._onOK = onOK

    P.input:SetText(defaultText or "")
    P.blocker:Show()
    P.box:Show()
    P.input:SetFocus()
    P.input:HighlightText()
  end

  -- ---------------------------------------------------------
  -- Page
  -- ---------------------------------------------------------
  local pProfiles = MakePage("Profiles", "Profiles")
  do
    -- Search (filters left list)
    local search = MakeInput(pProfiles, 360, 24)
    search:SetText("")

    local searchPH = MakeMutedText(search, "Search profiles…")
    searchPH:SetPoint("LEFT", 10, 0)
    searchPH:SetPoint("RIGHT", -10, 0)
    searchPH:SetJustifyH("LEFT")
    searchPH:SetAlpha(0.70)

    local function UpdateSearchPH()
      local hasText = (search:GetText() or "") ~= ""
      local hasFocus = search:HasFocus() and true or false
      searchPH:SetShown((not hasText) and (not hasFocus))
    end

    search:SetScript("OnEditFocusGained", UpdateSearchPH)
    search:SetScript("OnEditFocusLost", UpdateSearchPH)
    search:SetScript("OnTextChanged", function() UpdateSearchPH(); if UI.RefreshProfiles then UI:RefreshProfiles() end end)
    UpdateSearchPH()

    -- Panels
    local listPanel = MakePanel(pProfiles, PANEL)
    local right = MakePanel(pProfiles, PANEL)

    local listTitle = MakeSectionTitle(listPanel, "All profiles")
    listTitle:SetPoint("TOPLEFT", 12, -10)

    local listDiv = MakeDivider(listPanel)
    listDiv:SetPoint("TOPLEFT", 12, -34)
    listDiv:SetPoint("TOPRIGHT", -12, -34)

    local scroll = CreateFrame("ScrollFrame", nil, listPanel, "UIPanelScrollFrameTemplate")
  if Widgets and Widgets.SkinScrollBar and scroll.ScrollBar then Widgets:SkinScrollBar(scroll.ScrollBar) end
    scroll:SetPoint("TOPLEFT", 6, -40)
    scroll:SetPoint("BOTTOMRIGHT", -28, 10)

    local sc = CreateFrame("Frame", nil, scroll)
    sc:SetSize(1, 1)
    scroll:SetScrollChild(sc)

    local empty = MakeMutedText(listPanel, "No profiles found.")
    empty:SetPoint("TOPLEFT", 12, -60)
    empty:SetWidth(560)
    empty:SetJustifyH("LEFT")
    empty:Hide()

    -- Right header
    local rTitle = MakeSectionTitle(right, "Profile details")
    rTitle:SetPoint("TOPLEFT", 12, -10)

    local rDiv = MakeDivider(right)
    rDiv:SetPoint("TOPLEFT", 12, -34)
    rDiv:SetPoint("TOPRIGHT", -12, -34)

    local activeBadge = right:CreateFontString(nil, "OVERLAY", "WF_GameFontNormalSmall")
    activeBadge:SetPoint("TOPRIGHT", -12, -12)
    activeBadge:SetTextColor(C4(MUTED, MUTED))
    activeBadge:SetText("Active: —")

    local detailsText = MakeBodyText(right, "")
    detailsText:SetPoint("TOPLEFT", 12, -46)
    detailsText:SetPoint("TOPRIGHT", -12, -46)
    detailsText:SetJustifyH("LEFT")
    detailsText:SetJustifyV("TOP")
    detailsText:SetText("Select a profile on the left.")

    -- Actions
    local bSetActive = Widgets:Button(right, "Set Active", 110, 24)
    bSetActive:SetPoint("BOTTOMLEFT", 12, 12)

    local bSave = Widgets:Button(right, "Save Current →", 120, 24)
    bSave:SetPoint("LEFT", bSetActive, "RIGHT", 8, 0)

    local bDuplicate = Widgets:Button(right, "Duplicate", 96, 24)
    bDuplicate:SetPoint("LEFT", bSave, "RIGHT", 8, 0)

    local bRename = Widgets:Button(right, "Rename", 86, 24)
    bRename:SetPoint("LEFT", bDuplicate, "RIGHT", 8, 0)

    local bDelete = Widgets:Button(right, "Delete", 82, 24)
    bDelete:SetPoint("LEFT", bRename, "RIGHT", 8, 0)

    local bResetDefault = Widgets:Button(right, "Reset Preset", 112, 24)
    bResetDefault:SetPoint("LEFT", bDelete, "RIGHT", 8, 0)
    bResetDefault:Hide()

    -- List rows
    local rows = {}
    local rowH = 24
    local selectedName = nil

    local QUALITY = {
      [0] = "Poor+",
      [1] = "Common+",
      [2] = "Uncommon+",
      [3] = "Rare+",
      [4] = "Epic+",
      [5] = "Legendary+",
      [6] = "Artifact+",
      [7] = "Heirloom+",
    }

    local function EnsureRow(i)
      local r = rows[i]
      if r then return r end

      r = CreateFrame("Button", nil, sc)
      r:SetHeight(rowH)
      r:SetPoint("LEFT", 0, 0)
      r:SetPoint("RIGHT", 0, 0)

      r.bg = r:CreateTexture(nil, "BACKGROUND")
      r.bg:SetAllPoints(r)
      r.bg:SetTexture("Interface/Buttons/WHITE8x8")
      r.bg:SetAlpha(0)

      r.name = r:CreateFontString(nil, "OVERLAY", "WF_GameFontHighlight")
      r.name:SetPoint("LEFT", 12, 0)
      r.name:SetTextColor(C4(TEXT, TEXT))
      r.name:SetJustifyH("LEFT")

      r.meta = r:CreateFontString(nil, "OVERLAY", "WF_GameFontDisableSmall")
      r.meta:SetPoint("RIGHT", -12, 0)
      r.meta:SetTextColor(C4(MUTED, MUTED))

      r.sep = r:CreateTexture(nil, "BORDER")
      r.sep:SetTexture("Interface/Buttons/WHITE8x8")
      r.sep:SetHeight((Widgets and Widgets.PixelSize) and Widgets:PixelSize(r) or 1)
      if Widgets and Widgets.MakePixelPerfect then Widgets:MakePixelPerfect(r.sep, r) end
      r.sep:SetPoint("BOTTOMLEFT", 8, 0)
      r.sep:SetPoint("BOTTOMRIGHT", -8, 0)
      r.sep:SetAlpha(0.08)

      r:SetScript("OnEnter", function(self)
        if self._selected then return end
        self.bg:SetAlpha(0.08)
      end)
      r:SetScript("OnLeave", function(self)
        if self._selected then
          self.bg:SetAlpha(0.16)
        else
          self.bg:SetAlpha(0)
        end
      end)

      rows[i] = r
      return r
    end

    local function SetSelected(name)
      name = tostring(name or "")
      if name == "" then
        name = GetActiveProfileName()
      end

      selectedName = name
      UI._profilesSelectedName = name

      if UI.RefreshProfiles then UI:RefreshProfiles() end
    end

    local function BuildDetails(name)
      local prof = GetProfile(name)
      local active = GetActiveProfileName()

      activeBadge:SetText("Active: " .. DisplayProfileName(active or "Default"))

      if type(prof) ~= "table" then
        detailsText:SetText("Profile not found.\n\nSelect another profile.")
        bResetDefault:Hide()
        return
      end

      local lines = {}
      local function Add(k, v)
        lines[#lines + 1] = "|cffbdbdbd" .. k .. "|r  " .. tostring(v or "—")
      end

      Add("Name", DisplayProfileName(name))
      Add("Type", IsDefaultProfile(name) and "Preset (editable)" or "User")
      Add("Status", (name == active) and "Active" or "Idle")
      lines[#lines + 1] = " "

      if Util and Util.PrettyToken then
        Add("Price Source", Util:PrettyToken(prof.priceSource))
      else
        Add("Price Source", prof.priceSource or "—")
      end
      Add("Categories", CategorySummary(prof))
      Add("Ignore Soulbound", (prof.lootIgnoreSoulbound and "Yes" or "No"))
      Add("Min Qty", prof.lootMinQty or 0)
      Add("Min Quality", QUALITY[tonumber(prof.lootMinQuality) or 0] or tostring(prof.lootMinQuality or 0))
      Add("Min Value", Money(tonumber(prof.lootMinGold) or 0))
      if Util and Util.PrettyToken then
        Add("Overview Last 5", Util:PrettyToken(prof.overviewLast5Metric))
      else
        Add("Overview Last 5", prof.overviewLast5Metric or "—")
      end

      detailsText:SetText(table.concat(lines, "\n"))

      if IsDefaultProfile(name) and WF and WF.DB and WF.DB.ResetProfileToDefault then
        bResetDefault:Show()
      else
        bResetDefault:Hide()
      end
    end

    local function FilterAndSort(names, needle)
      needle = SafeTrim(needle)
      local needleL = Lower(needle)
      local out = {}
      for i = 1, #names do
        local n = names[i]
        local displayName = DisplayProfileName(n)
        local matches = (needle == "")
          or Lower(displayName):find(needleL, 1, true)
          or Lower(n):find(needleL, 1, true)
        if matches then
          out[#out + 1] = n
        end
      end

      table.sort(out, function(a, b)
        local ad = IsDefaultProfile(a) and 1 or 0
        local bd = IsDefaultProfile(b) and 1 or 0
        if ad ~= bd then return ad > bd end

        return tostring(a) < tostring(b)
      end)

      return out
    end

    function UI:RefreshProfiles()
      local names = GetProfileNames()
      local active = GetActiveProfileName()

      if not selectedName or selectedName == "" then
        selectedName = UI._profilesSelectedName or active or "Default"
      end

      -- If selection no longer exists, fall back.
      local exists = false
      for i = 1, #names do
        if names[i] == selectedName then exists = true break end
      end
      if not exists then selectedName = active or "Default" end

      BuildDetails(selectedName)

      local filtered = FilterAndSort(names, search:GetText() or "")
      empty:SetShown(#filtered == 0)

      local count = #filtered
      for i = 1, math.max(count, #rows) do
        local r = rows[i]
        local val = filtered[i]
        if val then
          r = EnsureRow(i)
          r:Show()
          r:SetPoint("TOPLEFT", 0, -((i - 1) * rowH))
          r:SetPoint("TOPRIGHT", 0, -((i - 1) * rowH))

          local meta = ""
          if val == active then
            meta = "Active"
          elseif IsDefaultProfile(val) then
            meta = "Preset"
          else
            meta = ""
          end

          r._value = val
          r.name:SetText(DisplayProfileName(val))
          r.meta:SetText(meta)

          r._selected = (val == selectedName)
          if r._selected then
            r.bg:SetAlpha(0.16)
          else
            r.bg:SetAlpha(0)
          end

          r:SetScript("OnClick", function()
            SetSelected(val)
          end)
        elseif r then
          r:Hide()
        end
      end

      sc:SetHeight(count * rowH)
      if count > 0 then
        local w = scroll:GetWidth()
        if w and w > 1 then sc:SetWidth(w) end
      end
    end

    local function ApplySelected()
      if not (WF and WF.DB and WF.DB.ApplyProfile) then return end
      local ok = WF.DB:ApplyProfile(selectedName)
      if ok then
        RefreshAfterProfileChange()
        if UI.RefreshProfiles then UI:RefreshProfiles() end
      end
    end

    local function SaveCurrentToSelected()
      if not (WF and WF.DB and WF.DB.SaveCurrentToProfile) then return end
      local ok = WF.DB:SaveCurrentToProfile(selectedName)
      if ok then
        if UI.RefreshProfiles then UI:RefreshProfiles() end
      end
    end

    local function DuplicateSelected()
      local baseName = tostring(selectedName or "Profile")
      local suffix = " Copy"
      local proposed = baseName .. suffix

      PromptText(
        "Duplicate Profile",
        "Create a new profile based on \"" .. baseName .. "\".",
        proposed,
        "Create",
        function(newName)
          newName = SafeTrim(newName)
          if newName == "" then return end
          if not (WF and WF.DB and WF.DB.SaveCurrentToProfile and WF.DB.ApplyProfile) then return end

          local src = GetProfile(baseName)
          if type(src) ~= "table" then return end

          -- Apply source temporarily, save to new profile, then restore active profile.
          local restore = GetActiveProfileName()
          WF.DB:ApplyProfile(baseName)
          WF.DB:SaveCurrentToProfile(newName)
          WF.DB:ApplyProfile(restore)

          UI._profilesSelectedName = newName
          selectedName = newName
          if UI.RefreshProfiles then UI:RefreshProfiles() end
        end
      )
    end

    local function RenameSelected()
      local oldName = tostring(selectedName or "")
      if oldName == "" then return end
      if not (WF and WF.DB and WF.DB.RenameProfile) then return end

      PromptText(
        "Rename Profile",
        "Rename \"" .. oldName .. "\" to:",
        oldName,
        "Rename",
        function(newName)
          newName = SafeTrim(newName)
          if newName == "" then return end

          local ok = WF.DB:RenameProfile(oldName, newName)
          if ok then
            UI._profilesSelectedName = newName
            selectedName = newName
            if UI.RefreshProfiles then UI:RefreshProfiles() end
            RefreshAfterProfileChange()
          end
        end
      )
    end

    local function DeleteSelected()
      local name = tostring(selectedName or "")
      if name == "" then return end
      if not (WF and WF.DB and WF.DB.DeleteProfile) then return end

      UI:Confirm(
        "Delete Profile",
        "Delete \"" .. name .. "\"?\n\nThis cannot be undone.",
        function()
          local ok = WF.DB:DeleteProfile(name)
          if ok then
            selectedName = GetActiveProfileName()
            UI._profilesSelectedName = selectedName
            if UI.RefreshProfiles then UI:RefreshProfiles() end
            RefreshAfterProfileChange()
          end
        end
      )
    end

    local function ResetPreset()
      local name = tostring(selectedName or "")
      if name == "" then return end
      if not (WF and WF.DB and WF.DB.ResetProfileToDefault) then return end
      if not IsDefaultProfile(name) then return end

      UI:Confirm(
        "Reset Preset",
        "Reset \"" .. name .. "\" back to the shipped preset?\n\nAny custom edits to this preset will be lost.",
        function()
          local ok = WF.DB:ResetProfileToDefault(name)
          if ok then
            if name == GetActiveProfileName() then
              WF.DB:ApplyProfile(name)
              RefreshAfterProfileChange()
            end
            if UI.RefreshProfiles then UI:RefreshProfiles() end
          end
        end
      )
    end

    bSetActive:SetScript("OnClick", ApplySelected)
    bSave:SetScript("OnClick", SaveCurrentToSelected)
    bDuplicate:SetScript("OnClick", DuplicateSelected)
    bRename:SetScript("OnClick", RenameSelected)
    bDelete:SetScript("OnClick", DeleteSelected)
    bResetDefault:SetScript("OnClick", ResetPreset)

    -- Hook show
    pProfiles:SetScript("OnShow", function()
      UI:_Layout()
      if UI.RefreshProfiles then UI:RefreshProfiles() end
    end)

    self._layout.profiles = {
      page = pProfiles,
      search = search,
      listPanel = listPanel,
      right = right,
      detailsText = detailsText,
    }
  end
end