local ADDON_NAME = ...
local BFH = CreateFrame("Frame")
_G.BlightfallHelper = BFH

BFH.VERSION = "2.1.1"
BFH.SCHEMA = 4

BFH.SPELL = {
    DARK_TRANSFORMATION = 1233448,
    SOUL_REAPER = 343294,
    BLIGHTFALL = 1271967,
}

BFH.defaults = {
    schemaVersion = BFH.SCHEMA,

    enabled = true,
    displayMode = "BAR",
    locked = true,

    showMinimapButton = true,
    minimapAngle = 225,

    soulDelay = 7.0,
    blightDelay = 7.0,
    countdownStart = 4,
    precision = 1,

    soundEnabled = true,
    audioMode = "FILES", -- FILES / TTS
    soundChannel = "Master",
    ttsVolume = 80,
    ttsRate = 0,
    ttsVoiceID = nil,

    scale = 1.00,
    barWidth = 200,
    barHeight = 20,
    showIcon = true,
    iconPosition = "LEFT",
    iconSize = 20,
    iconOnlySize = 64,

    font = "Fonts\\FRIZQT__.TTF",
    fontName = "Friz Quadrata",
    labelFontSize = 14,
    timerFontSize = 14,

    showSpark = true,
    borderEnabled = true,
    backgroundAlpha = 0.90,

    soulColor = {0x1C/255, 0x28/255, 0xFF/255, 1},
    blightColor = {0x9F/255, 0x1C/255, 0xFF/255, 1},
    dangerColor = {0xFF/255, 0x00/255, 0x10/255, 1},

    point = "CENTER",
    relativePoint = "CENTER",
    x = 0,
    y = 0,

    configWidth = 1040,
    configHeight = 700,

    activeProfile = "Default",
    profiles = { Default = {} },
}

local function DeepCopy(src)
    if type(src) ~= "table" then return src end
    local dst = {}
    for k, v in pairs(src) do dst[k] = DeepCopy(v) end
    return dst
end
BFH.DeepCopy = DeepCopy

local function CopyDefaults(src, dst)
    for k, v in pairs(src) do
        if type(v) == "table" then
            if type(dst[k]) ~= "table" then dst[k] = {} end
            CopyDefaults(v, dst[k])
        elseif dst[k] == nil then
            dst[k] = v
        end
    end
end
BFH.CopyDefaults = CopyDefaults

local function Migrate(db)
    local old = tonumber(db.schemaVersion) or 0
    if old < 4 then
        db.soulColor = {0x1C/255, 0x28/255, 0xFF/255, 1}
        db.blightColor = {0x9F/255, 0x1C/255, 0xFF/255, 1}
        db.dangerColor = {0xFF/255, 0x00/255, 0x10/255, 1}
        db.showIcon = true
        db.iconPosition = "LEFT"
        db.showMinimapButton = true
        db.audioMode = db.audioMode or "FILES"
        db.ttsVolume = db.ttsVolume or 80
        db.ttsRate = db.ttsRate or 0
        db.configWidth = math.max(900, tonumber(db.configWidth) or 1040)
        db.configHeight = math.max(600, tonumber(db.configHeight) or 700)
        db.schemaVersion = 4
    end
end

function BFH:GetSpellTexture(spellID)
    local texture
    if C_Spell and C_Spell.GetSpellTexture then
        texture = C_Spell.GetSpellTexture(spellID)
    end
    if not texture and C_Spell and C_Spell.GetSpellInfo then
        local info = C_Spell.GetSpellInfo(spellID)
        texture = info and info.iconID
    end
    if not texture and GetSpellTexture then
        texture = GetSpellTexture(spellID)
    end
    return texture or 134400
end

function BFH:GetSoundPath(number)
    return string.format("Interface\\AddOns\\BlightfallHelper\\Sounds\\%d.ogg", number)
end

function BFH:GetTTSVoices()
    if C_VoiceChat and C_VoiceChat.GetTtsVoices then
        local ok, voices = pcall(C_VoiceChat.GetTtsVoices)
        if ok and type(voices) == "table" then return voices end
    end
    return {}
end

function BFH:GetTTSVoiceID()
    local voices = self:GetTTSVoices()
    if #voices == 0 then return nil end

    if self.db.ttsVoiceID then
        for _, voice in ipairs(voices) do
            if voice.voiceID == self.db.ttsVoiceID then
                return self.db.ttsVoiceID
            end
        end
    end

    self.db.ttsVoiceID = voices[1].voiceID
    return self.db.ttsVoiceID
end

function BFH:StopTTS()
    if C_VoiceChat and C_VoiceChat.StopSpeakingText then
        pcall(C_VoiceChat.StopSpeakingText)
    end
end

function BFH:PlayCountdown(number)
    if not self.db.soundEnabled then return end
    if number < 1 or number > 10 then return end

    if self.db.audioMode == "TTS" then
        local voiceID = self:GetTTSVoiceID()
        if not voiceID or not C_VoiceChat or not C_VoiceChat.SpeakText then return end
        self:StopTTS()
        pcall(
            C_VoiceChat.SpeakText,
            voiceID,
            tostring(number),
            tonumber(self.db.ttsRate) or 0,
            tonumber(self.db.ttsVolume) or 80,
            false
        )
    else
        PlaySoundFile(self:GetSoundPath(number), self.db.soundChannel or "Master")
    end
end

function BFH:HandleSpell(spellID)
    if not self.db.enabled then return end

    if spellID == self.SPELL.DARK_TRANSFORMATION then
        self.sequenceArmed = true
        self.soulUsed = false
        self.blightUsed = false
        self:StartStage("SOUL", self.db.soulDelay)
        return
    end

    if spellID == self.SPELL.SOUL_REAPER then
        if self.sequenceArmed and not self.soulUsed then
            self.soulUsed = true
            if self.stage == "SOUL" then self:StopStage() end
            self:StartStage("BLIGHT", self.db.blightDelay)
        end
        return
    end

    if spellID == self.SPELL.BLIGHTFALL then
        if self.sequenceArmed and self.soulUsed and not self.blightUsed then
            self.blightUsed = true
            if self.stage == "BLIGHT" then self:StopStage() end
            self.sequenceArmed = false
        end
    end
end

function BFH:ResetSequence()
    self.sequenceArmed = false
    self.soulUsed = false
    self.blightUsed = false
    if self.StopStage then self:StopStage() end
end

BFH:RegisterEvent("ADDON_LOADED")
BFH:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
BFH:RegisterEvent("PLAYER_ENTERING_WORLD")

BFH:SetScript("OnEvent", function(self, event, ...)
    if event == "ADDON_LOADED" then
        local name = ...
        if name ~= ADDON_NAME then return end

        BlightfallHelperDB = BlightfallHelperDB or {}
        CopyDefaults(self.defaults, BlightfallHelperDB)
        Migrate(BlightfallHelperDB)
        self.db = BlightfallHelperDB

        if self.InitializeDisplay then self:InitializeDisplay() end
        if self.InitializeMinimapButton then self:InitializeMinimapButton() end
        if self.InitializeConfig then self:InitializeConfig() end

        SLASH_BLIGHTFALLHELPER1 = "/bfh"
        SlashCmdList.BLIGHTFALLHELPER = function(msg)
            msg = (msg or ""):lower():match("^%s*(.-)%s*$")
            if msg == "unlock" then
                self.db.locked = false
                self:ApplyDisplaySettings()
                self:ShowPreview("SOUL")
            elseif msg == "lock" then
                self.db.locked = true
                self:ApplyDisplaySettings()
                self:StopStage()
            elseif msg == "test" then
                self:ShowPreview("SOUL")
            elseif msg == "stop" then
                self:StopStage()
            else
                self:ToggleConfig()
            end
        end

        print("|cff9f1cffBlightfallHelper|r v"..self.VERSION.." loaded. Type |cffffffff/bfh|r for settings.")
    elseif event == "PLAYER_ENTERING_WORLD" then
        self:ResetSequence()
    elseif event == "UNIT_SPELLCAST_SUCCEEDED" then
        local unit, _, spellID = ...
        if unit == "player" then self:HandleSpell(spellID) end
    end
end)
