local SlickUI = _G.SlickUI
if not SlickUI or not SlickUI.Fishing then return end

local Ledger = { CharacterScope = "current", ZoneScope = "current", Period = "session", Rows = {} }
SlickUI.FishingLedger = Ledger

local function Settings() return SlickUI.DB.fishing end
local function CharacterKey() return (UnitName("player") or "Unknown") .. " - " .. (GetRealmName() or "Unknown Realm") end
local function CurrentMap() return C_Map.GetBestMapForUnit("player") or 0 end

local function ItemDisplay(itemID)
	local name, _, quality = C_Item.GetItemInfo(itemID)
	if not name then C_Item.RequestLoadItemDataByID(itemID) end
	name = name or C_Item.GetItemNameByID(itemID) or ("Item " .. itemID)
	local color = quality and ITEM_QUALITY_COLORS and ITEM_QUALITY_COLORS[quality]
	return name, color
end

local function FormatDuration(seconds)
	seconds = math.max(0, math.floor(seconds or 0))
	local hours = math.floor(seconds / 3600)
	local minutes = math.floor((seconds % 3600) / 60)
	return string.format("%02d:%02d:%02d", hours, minutes, seconds % 60)
end

function Ledger:UpdatePersistentSummary()
	if not self.Window then return end
	local allTime = SlickUI.Fishing:GetAllTimeTotal(false, false)
	self.Window.PersistentSummary:SetText(string.format(
		"Active Session: |cff55bfff%s|r    Lifetime Fishing: |cffb58cff%s|r    All-Time Catches: |cff42df72%d|r",
		FormatDuration(SlickUI.Fishing:GetSessionSeconds()), FormatDuration(SlickUI.Fishing:GetLifetimeSeconds(false)), allTime
	))
end

function Ledger:RefreshLure()
	if not self.Window or not self.Window.LureButton then return end
	local button = self.Window.LureButton
	local itemID, link, icon, count, bonus, bagID, slotID = SlickUI.Fishing:FindAvailableLure()
	local applied = SlickUI.Fishing:HasPoleLure()
	button.ItemLink = link
	button.Icon:SetTexture(icon or 134335)
	button.Count:SetText(itemID and count and count > 1 and count or "")
	self.Window.LureStatus:SetText(applied and "|cff42df72Lure applied|r" or (itemID and (bonus > 0 and ("|cffffb347Best lure: +" .. bonus .. "|r") or "|cffffb347Apply lure|r") or "|cff999999No lure available|r"))
	if not InCombatLockdown() then
		button:SetShown(itemID ~= nil)
		button:SetAttribute("type1", itemID and "item" or nil)
		button:SetAttribute("item1", itemID and (bagID .. " " .. slotID) or nil)
	end
end

function Ledger:Collect()
	local items, total = {}, 0
	local character, mapID = CharacterKey(), CurrentMap()
	local source = self.Period == "session" and SlickUI.Fishing.SessionEntries or Settings().entries
	for _, entry in ipairs(source) do
		if (self.CharacterScope == "all" or entry.character == character) and (self.ZoneScope == "all" or entry.mapID == mapID) then
			local item = items[entry.itemID]
			if not item then
				item = { itemID = entry.itemID, quantity = 0, zones = {} }
				items[entry.itemID] = item
			end
			item.quantity = item.quantity + entry.quantity
			item.zones[entry.zone or "Unknown Zone"] = true
			total = total + entry.quantity
		end
	end
	local sorted = {}
	for _, item in pairs(items) do
		local zones = {}
		for zone in pairs(item.zones) do zones[#zones + 1] = zone end
		table.sort(zones)
		item.zoneText = table.concat(zones, ", ")
		sorted[#sorted + 1] = item
	end
	table.sort(sorted, function(a, b) if a.quantity == b.quantity then return a.itemID < b.itemID end return a.quantity > b.quantity end)
	return sorted, total
end

function Ledger:Refresh()
	if not self.Window then return end
	local data, total = self:Collect()
	local elapsed = math.max(1, SlickUI.Fishing:GetSessionSeconds())
	local rate = SlickUI.Fishing.SessionTotal * 3600 / elapsed
	self:UpdatePersistentSummary()
	self:RefreshLure()
	self.Window.Summary:SetText(string.format("Current View: |cff42df72%d|r caught    Unique: |cff55bfff%d|r    Session Rate: %.1f/hour", total, #data, rate))
	self.Window.Character:SetText(self.CharacterScope == "all" and "All Characters" or "Current Character")
	self.Window.Zone:SetText(self.ZoneScope == "all" and "All Zones" or (GetZoneText() or "Current Zone"))
	self.Window.Period:SetText(self.Period == "session" and "This Session" or "All Time")
	for _, row in ipairs(self.Rows) do row:Hide() end
	for index, entry in ipairs(data) do
		local row = self.Rows[index]
		if not row then
			row = CreateFrame("Frame", nil, self.Window.List)
			row:SetHeight(34); row:SetPoint("TOPLEFT", 0, -((index - 1) * 35)); row:SetPoint("RIGHT")
			row.IconButton = CreateFrame("Button", nil, row)
			row.IconButton:SetSize(30, 30); row.IconButton:SetPoint("LEFT", 2, 0)
			row.Icon = row.IconButton:CreateTexture(nil, "ARTWORK"); row.Icon:SetAllPoints(); row.Icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
			row.IconButton:SetScript("OnEnter", function(self)
				if not self.ItemID then return end
				GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
				GameTooltip:SetHyperlink("item:" .. self.ItemID)
				GameTooltip:Show()
			end)
			row.IconButton:SetScript("OnLeave", GameTooltip_Hide)
			row.Name = row:CreateFontString(nil, "ARTWORK", "GameFontHighlight"); row.Name:SetPoint("LEFT", row.IconButton, "RIGHT", 9, 0); row.Name:SetWidth(250); row.Name:SetJustifyH("LEFT"); row.Name:SetWordWrap(false)
			row.ZoneName = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall"); row.ZoneName:SetPoint("LEFT", 330, 0); row.ZoneName:SetWidth(230); row.ZoneName:SetJustifyH("LEFT"); row.ZoneName:SetWordWrap(false); row.ZoneName:SetTextColor(0.72, 0.74, 0.80)
			row.Count = row:CreateFontString(nil, "ARTWORK", "GameFontNormal"); row.Count:SetPoint("RIGHT", -8, 0)
			self.Rows[index] = row
		end
		local name, color = ItemDisplay(entry.itemID)
		row.Icon:SetTexture(C_Item.GetItemIconByID(entry.itemID) or 134400)
		row.IconButton.ItemID = entry.itemID
		row.Name:SetText(name)
		if color then row.Name:SetTextColor(color.r, color.g, color.b) else row.Name:SetTextColor(1, 1, 1) end
		row.ZoneName:SetText(self.ZoneScope == "all" and entry.zoneText or "")
		row.ZoneName:SetShown(self.ZoneScope == "all")
		row.Count:SetText(entry.quantity)
		row:Show()
	end
	self.Window.List:SetHeight(math.max(1, #data * 35))
	self.Window.Empty:SetShown(#data == 0)
end

function Ledger:CreateWindow()
	if self.Window then return end
	local window = CreateFrame("Frame", "SlickUIFishingLedger", UIParent, "BackdropTemplate")
	window:SetSize(760, 610); window:SetPoint("CENTER"); window:SetFrameStrata("DIALOG"); window:SetClampedToScreen(true)
	window:SetMovable(true); window:EnableMouse(true); window:RegisterForDrag("LeftButton")
	window:SetScript("OnDragStart", window.StartMoving); window:SetScript("OnDragStop", window.StopMovingOrSizing)
	window:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 2 })
	window:SetBackdropColor(0.015, 0.018, 0.025, 0.97); window:SetBackdropBorderColor(1, 0.58, 0, 1)
	table.insert(UISpecialFrames, window:GetName())
	local title = window:CreateFontString(nil, "ARTWORK", "GameFontNormalHuge"); title:SetPoint("TOPLEFT", 20, -18); title:SetText("SlickUI Fishing Ledger")
	local close = CreateFrame("Button", nil, window, "UIPanelCloseButton"); close:SetPoint("TOPRIGHT", -4, -4)
	local journalButton = CreateFrame("Button", nil, window, "BackdropTemplate")
	journalButton:SetSize(34, 34); journalButton:SetPoint("TOPRIGHT", -48, -45)
	journalButton:SetBackdrop({ edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1 }); journalButton:SetBackdropBorderColor(1, 0.58, 0, 1)
	journalButton.Icon = journalButton:CreateTexture(nil, "ARTWORK"); journalButton.Icon:SetAllPoints(); journalButton.Icon:SetTexture(136245); journalButton.Icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
	journalButton:SetScript("OnClick", function()
		if InCombatLockdown() then
			SlickUI:Print("The Fishing Journal cannot be opened during combat.")
			return
		end
		local profession = Enum.Profession and Enum.Profession.Fishing
		local skillLineID = profession and C_TradeSkillUI.GetProfessionSkillLineID(profession)
		if skillLineID then C_TradeSkillUI.OpenTradeSkill(skillLineID) else ToggleProfessionsBook() end
	end)
	journalButton:SetScript("OnEnter", function(self)
		GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); GameTooltip:SetText("Open Fishing Journal")
		GameTooltip:AddLine("Click to show your equipped fishing pole.", 0.65, 0.68, 0.75); GameTooltip:Show()
	end)
	journalButton:SetScript("OnLeave", GameTooltip_Hide)
	window.JournalButton = journalButton
	local lureButton = CreateFrame("Button", "SlickUIFishingLureButton", window, "SecureActionButtonTemplate,BackdropTemplate")
	lureButton:SetSize(34, 34); lureButton:SetPoint("RIGHT", journalButton, "LEFT", -8, 0)
	lureButton:SetBackdrop({ edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = 1 })
	lureButton:SetBackdropBorderColor(1, 0.58, 0, 1)
	lureButton.Icon = lureButton:CreateTexture(nil, "ARTWORK"); lureButton.Icon:SetAllPoints(); lureButton.Icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
	lureButton.Count = lureButton:CreateFontString(nil, "OVERLAY", "NumberFontNormal"); lureButton.Count:SetPoint("BOTTOMRIGHT", -2, 2)
	lureButton:SetAttribute("useOnKeyDown", false)
	lureButton:RegisterForClicks("AnyUp", "AnyDown")
	lureButton:SetScript("OnEnter", function(self)
		GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
		if self.ItemLink then GameTooltip:SetHyperlink(self.ItemLink) else GameTooltip:SetText("No fishing lure available") end
		GameTooltip:AddLine("Click to apply this lure.", 0.65, 0.68, 0.75)
		GameTooltip:Show()
	end)
	lureButton:SetScript("OnLeave", GameTooltip_Hide)
	window.LureButton = lureButton
	local lureStatus = window:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
	lureStatus:SetPoint("RIGHT", lureButton, "LEFT", -8, 0); window.LureStatus = lureStatus
	local lureHelp = window:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
	lureHelp:SetPoint("TOPRIGHT", journalButton, "BOTTOMRIGHT", 0, -6); lureHelp:SetWidth(360); lureHelp:SetJustifyH("RIGHT"); lureHelp:SetWordWrap(true)
	lureHelp:SetText("Apply lure: click lure icon, open the Fishing Journal, then click your fishing pole.")
	window.LureHelp = lureHelp
	local persistentSummary = window:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
	persistentSummary:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -10)
	window.PersistentSummary = persistentSummary
	local summary = window:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
	summary:SetPoint("TOPLEFT", persistentSummary, "BOTTOMLEFT", 0, -7)
	window.Summary = summary

	local function FilterButton(x, width, click)
		local button = CreateFrame("Button", nil, window, "UIPanelButtonTemplate")
		button:SetSize(width, 25); button:SetPoint("TOPLEFT", x, -98); button:SetScript("OnClick", click); return button
	end
	window.Character = FilterButton(20, 170, function() Ledger.CharacterScope = Ledger.CharacterScope == "all" and "current" or "all"; Ledger:Refresh() end)
	window.Zone = FilterButton(200, 150, function() Ledger.ZoneScope = Ledger.ZoneScope == "all" and "current" or "all"; Ledger:Refresh() end)
	window.Period = FilterButton(360, 140, function() Ledger.Period = Ledger.Period == "session" and "all" or "session"; Ledger:Refresh() end)
	local reset = FilterButton(510, 145, function()
		local wasActive = SlickUI.Fishing.ActiveStartedAt ~= nil
		SlickUI.Fishing:CommitActiveTime()
		wipe(SlickUI.Fishing.Session)
		wipe(SlickUI.Fishing.SessionEntries)
		SlickUI.Fishing.SessionTotal = 0
		SlickUI.Fishing.SessionSeconds = 0
		if wasActive then SlickUI.Fishing:StartActiveTime() end
		Ledger:Refresh()
	end); reset:SetText("Reset Session")

	local scroll = CreateFrame("ScrollFrame", nil, window, "UIPanelScrollFrameTemplate")
	scroll:SetPoint("TOPLEFT", 20, -138); scroll:SetPoint("BOTTOMRIGHT", -38, 20)
	local list = CreateFrame("Frame", nil, scroll); list:SetWidth(610); list:SetHeight(1); scroll:SetScrollChild(list); window.List = list
	local empty = list:CreateFontString(nil, "ARTWORK", "GameFontDisableLarge"); empty:SetPoint("TOP", 0, -60); empty:SetText("No fishing catches recorded for this view."); window.Empty = empty
	self.Window = window
	local events = CreateFrame("Frame")
	events:RegisterEvent("GET_ITEM_INFO_RECEIVED")
	events:RegisterEvent("BAG_UPDATE_DELAYED")
	events:RegisterEvent("PLAYER_REGEN_ENABLED")
	events:SetScript("OnEvent", function()
		if Ledger.Window and Ledger.Window:IsShown() then Ledger:Refresh() end
	end)
	self.ItemEvents = events
	window:SetScript("OnUpdate", function(_, elapsed)
		Ledger.TimerElapsed = (Ledger.TimerElapsed or 0) + elapsed
		if Ledger.TimerElapsed >= 1 then
			Ledger.TimerElapsed = 0
			Ledger:UpdatePersistentSummary()
		end
	end)
end

function Ledger:Show()
	self:CreateWindow(); self:Refresh(); self.Window:Show(); self.Window:Raise()
end

function Ledger:Toggle()
	if self.Window and self.Window:IsShown() then self.Window:Hide() else self:Show() end
end
