-- lx format
local format = require("core.format")
local patterns = require("core.format.patterns")
local quotes = require("core.quotes")

format.register({
	name = "PHP Script",
	shortname = "PHP",
	extensions = {
		"php",
		"php8",
		"php7",
		"php5",
		"php4",
		"php3",
		"phps",
		"phpt",
		"phtml",
	},
	comment = "//",

	headers = {
		"%<%?php",
		"^#!.*[ /]php",
	},

	patterns = {
		patterns.shebang_line(),

		-- Hand non-PHP text to HTML, which also recognizes embedded scripts and styles
		-- Pattern breakdown: start after the PHP close tag and return at the next standard PHP open tag
		{ pattern = { "%?>", "<%?php" }, type = "meta", delim_type = "meta", syntax = ".html" },

		-- PHP open/close tags (including short forms) as meta markers
		{ pattern = "<%?php", type = "meta" },
		{ pattern = "<%?=", type = "meta" },
		{ pattern = "<%?", type = "meta" },
		{ pattern = "%?>", type = "meta" },

		-- File Inclusion
--		{ pattern = "require%s*%(?%s*[^%)]-%s*%)?", type = "preprocessor" },
--		{ pattern = "require_once%s*%(?%s*[^%)]-%s*%)?", type = "preprocessor" },
--		{ pattern = "include%s*%(?%s*[^%)]-%s*%)?", type = "preprocessor" },
--		{ pattern = "include_once%s*%(?%s*[^%)]-%s*%)?", type = "preprocessor" },
--		{ pattern = "define%s*%(?%s*[^%)]-%s*%)?", type = "preprocessor" },

		-- PHP 8 attributes
		{ pattern = "#%b[]", type = "meta" }, -- #[...]

		-- Comments
		{ pattern = "//.-\n", type = "comment" },
		{ pattern = { "/%*", "%*/" }, type = "comment" },

		-- Heredoc and nowdoc
		{ pattern = "<<<?%s*['\"]?[%a_][%w_]*['\"]?.-\n[%a_][%w_]*;?", type = "string" },

		-- Strings
		{ pattern = { '"', '"', "\\" }, type = "string" },
		{ pattern = { "'", "'", "\\" }, type = "string" },

		-- Numbers
		{ pattern = "%\\x[%da-fA-F]+", type = "hex" },
		{ pattern = "-?%d+[%d%.eE]*", type = "number" },
		{ pattern = "-?%.?%d+", type = "number" },

		{ pattern = "[%.%+%-=/%*%^%%<>!~|&]", type = "operator" },
		{ pattern = "[%a_][%w_]*%f[(]", type = "function" },

		-- Highlight PHP variables as a single token (e.g. $unwantedReason)
		{ pattern = "%$+[%a_][%w_]*", type = "variable" },
		{ pattern = "[%a_][%w_]*", type = "symbol" },

		-- Special variable
		{ pattern = "%$this%f[^%w_]", type = "keyword2" },

		-- To indicate variables
		{ pattern = "%$", type = "operator" },

	},

	outline_patterns = {
		{ pattern = "%s*class%s+[%a_][%w_]*", line_start = true },
		{ pattern = "%s*interface%s+[%a_][%w_]*", line_start = true },
		{ pattern = "%s*trait%s+[%a_][%w_]*", line_start = true },
		{ pattern = "%s*enum%s+[%a_][%w_]*", line_start = true },
		{ pattern = "%s*function%s+[%a_][%w_]*%s*%b()", line_start = true },
		{ pattern = "%s*[%a_%s]+function%s+[%a_][%w_]*%s*%b()", line_start = true },
		{ pattern = "%s*namespace%s+[%a_\\][%w_\\]*", line_start = true },
		{ pattern = "%s*use%s+[%a_\\][%w_\\]*", line_start = true },
	},

	block_comment = {
		block_open = "/*",
		block_close = "*/",
		block_line_prefix = " * ",
		close_line_prefix = " ",
		open_on_own_line = false,
		close_on_own_line = true,
		strip_line_prefix = "^%s*%*%s?",
		allow_nested = false,
	},

	guard_comment = {
		guard_open = { "if (false) {", "if (0) {" },
		guard_close = "}",
		guard_body_prefix = "auto",
		guard_align_to_indent = true,
		allow_nested = true,
	},

	quotes = {
		primary = "double",
		secondary = "single",
		profiles = {
			double = quotes.profile.c_style_double(),
			single = quotes.profile.c_style_single(),
		},
	},

	symbols = {
		-- Control Flow
		["break"] = "keyword", -- Exit loop or switch
		["case"] = "keyword", -- Switch case label
		["continue"] = "keyword", -- Skip to next loop iteration
		["default"] = "keyword", -- Switch default case
		["do"] = "keyword", -- Start of do-while loop
		["else"] = "keyword", -- If-else branch
		["elseif"] = "keyword", -- Combined else-if
		["for"] = "keyword", -- Standard for loop
		["foreach"] = "keyword", -- Array/object iteration
		["goto"] = "keyword", -- Jump to label
		["if"] = "keyword", -- Conditional branch
		["match"] = "keyword", -- Match expression (PHP 8.0+)
		["return"] = "keyword", -- Exit function and return value
		["switch"] = "keyword", -- Multi-way branch
		["while"] = "keyword", -- Standard while loop
		["yield"] = "keyword", -- Generator yield
		["yield from"] = "keyword", -- Delegate to another generator

		-- Alternative Syntax (Templates)
		["endfor"] = "keyword",
		["endforeach"] = "keyword",
		["endif"] = "keyword",
		["endswitch"] = "keyword",
		["endwhile"] = "keyword",
		["enddeclare"] = "keyword",

		-- Declarations and OOP
		["abstract"] = "keyword", -- Class or method abstraction
		["as"] = "keyword", -- Alias in foreach or use
		["class"] = "keyword", -- Define a class
		["enum"] = "keyword", -- Define an enumeration (PHP 8.1+)
		["final"] = "keyword", -- Prevent overriding/inheritance
		["function"] = "keyword", -- Declare a function
		["fn"] = "keyword", -- Arrow function (PHP 7.4+)
		["interface"] = "keyword", -- Define an interface
		["namespace"] = "keyword", -- Define a namespace
		["new"] = "keyword", -- Instantiate an object
		["private"] = "keyword", -- Visibility: class only
		["protected"] = "keyword", -- Visibility: class and subclasses
		["public"] = "keyword", -- Visibility: accessible everywhere
		["readonly"] = "keyword", -- Read-only property (PHP 8.1+)
		["static"] = "keyword", -- Static member or late static binding
		["trait"] = "keyword", -- Define a trait
		["use"] = "keyword", -- Import namespace or use trait
		["insteadof"] = "keyword", -- Trait conflict resolution

		-- Language Constructs & Output
		["declare"] = "keyword", -- Set execution directives
		["echo"] = "keyword", -- Output one or more strings
		["empty"] = "keyword", -- Check if variable is empty
		["exit"] = "keyword", -- Terminate script execution
		["global"] = "keyword", -- Access global variables
		["instanceof"] = "keyword", -- Type check
		["isset"] = "keyword", -- Check if variable is set
		["list"] = "keyword", -- Destructure array into variables
		["print"] = "keyword", -- Output a string
		["throw"] = "keyword", -- Explicitly throw exception
		["try"] = "keyword", -- Error handling block
		["catch"] = "keyword", -- Handle exception
		["finally"] = "keyword", -- Always executed block
		["unset"] = "keyword", -- Destroy a variable

		-- "Preprocessor"
		["include"] = "preprocessor",
		["include_once"] = "preprocessor",
		["require"] = "preprocessor",
		["require_once"] = "preprocessor",
		["define"] = "preprocessor",

		-- Types and Inheritance
		["array"] = "keyword2",
		["bool"] = "keyword2",
		["boolean"] = "keyword2",
		["callable"] = "keyword2",
		["clone"] = "keyword2", -- Object cloning
		["const"] = "keyword2", -- Define a constant
		["double"] = "keyword2",
		["extends"] = "keyword2", -- Class/interface extension
		["float"] = "keyword2",
		["implements"] = "keyword2", -- Interface implementation
		["int"] = "keyword2",
		["integer"] = "keyword2",
		["iterable"] = "keyword2",
		["object"] = "keyword2",
		["real"] = "keyword2",
		["string"] = "keyword2",
		["var"] = "keyword2", -- Legacy property declaration

		-- Literals and References
		["false"] = "literal",
		["true"] = "literal",
		["NULL"] = "literal",
		["null"] = "literal", -- Case-insensitive in PHP
		["parent"] = "literal", -- Reference parent class
		["self"] = "literal", -- Reference current class

		-- Magic Constants
		["__DIR__"] = "constant", -- Current directory
		["__FILE__"] = "constant", -- Current file path
		["__LINE__"] = "constant", -- Current line number
		["__NAMESPACE__"] = "constant", -- Current namespace
		["__CLASS__"] = "constant", -- Current class name
		["__TRAIT__"] = "constant", -- Current trait name
		["__METHOD__"] = "constant", -- Current class method name
		["__FUNCTION__"] = "constant", -- Current function name

		-- Superglobals
		["$GLOBALS"] = "bold", -- TODO: Type "superglobal" or similar
		["$_SERVER"] = "bold",
		["$_GET"] = "bold",
		["$_POST"] = "bold",
		["$_FILES"] = "bold",
		["$_REQUEST"] = "bold",
		["$_SESSION"] = "bold",
		["$_COOKIE"] = "bold",
		["$_ENV"] = "bold",

		-- Predefined variables, not superglobal, but we can only highlight them one way
		-- TODO: Type "predefined"??
		["$php_errormsg"] = "keyword2", -- The previous error message
		["$http_response_header"] = "keyword2", -- HTTP response headers
		["$argc"] = "keyword2", -- The number of arguments passed to script
		["$argv"] = "keyword2", -- Array of arguments passed to script
	},
})
