-- lx-bundle:true

local Object = require("core.object")
local config = require("core.config")
local lifecycle = require("core.doc.lifecycle")
local undo = require("core.doc.undo")

local Doc = Object:extend()

-- Keep Doc method ownership explicit instead of routing through install/shared
for name, fn in pairs({
	undo = undo.undo,
	redo = undo.redo,
}) do
	Doc[name] = fn
end

-- Load integrated doc monitor module without auto-start side effects
require("core.doc.monitor")

--- Initializes a document and optionally opens it from disk
-- @param filename string|nil file path
-- @param opts table|nil lifecycle options
function Doc:new(filename, opts)
	self:reset()

	-- Base documents only open from disk when a subtype provides lifecycle I/O
	if filename and type(self.open) == "function" then
		self:open(filename, opts)
	end
end

-- Resets document content, undo state, and cursor selection
function Doc:reset()
	self.lines = { "\n" }
	self.longest_line_length = 0
	self.longest_line_index = 1
	self.selection = {
		start = { line = 1, col = 1 },
		stop = { line = 1, col = 1 },
	}
	self.undo_stack = { idx = 1 }
	self.redo_stack = { idx = 1 }
	self.clean_change_id = 1

	self.file_bom = false
	self.file_encoding = "utf8"
	self.file_codepage = nil
	self.is_actual_file = false
	self.is_binary = false
	self.is_image = false
	self.encoding_label = "UTF-8"
	self.codepage_label = nil
	self.save_disabled = false
	self.save_disabled_reason = nil
	self.syntax = nil
	self.syntax_detect_meta = nil
	self.highlighter = nil
	self._last_text_change = nil

	-- Track EOF EOL sequence and count for exact round-trips
	self.eof_eol_sequence = "\n"
	self.eof_eol_count = 1
end

-- Base documents do not own syntax or highlighter state
function Doc:reset_syntax()
	return nil
end

--- Replay one undo entry for this document type
-- Base documents do not define undo replay behavior
-- @param cmd table undo entry to replay
-- @param redo_stack table target stack for inverse entries
-- @return boolean|nil true when applied, false when unsupported
function Doc:apply_undo_entry(cmd, redo_stack)
	return false
end

-- Returns the filename or a fallback label for unsaved docs
function Doc:get_name()
	return self.filename or config.default_doc_title or "untitled"
end

-- Returns true if document content differs from the last clean mark
function Doc:is_dirty()
	return self.clean_change_id ~= self:get_change_id()
end

-- Marks the current change id as the clean state
function Doc:clean()
	self.clean_change_id = self:get_change_id()
end

-- Returns the current monotonic document change id
function Doc:get_change_id()
	return self.undo_stack.idx
end

--- Return one detected document type description for a path
-- @param filename string|nil file path
-- @param opts table|nil detect options
-- @return table|nil probe
-- @return string|nil err
Doc.detect_type = lifecycle.detect_type

--- Create a new text document through the universal lifecycle owner
-- @param filename string|nil synthetic filename
-- @param opts table|nil lifecycle options
-- @return table|nil doc
Doc.create = lifecycle.create

--- Open or reuse a document through the universal lifecycle owner
-- @param filename string file path
-- @param opts table|nil lifecycle options
-- @return table|nil doc
Doc.open_file = lifecycle.open_file

return Doc
