use fancy_regex::Regex;
use lazy_static::lazy_static;

lazy_static! {

    /// The following regex is used as a detector for AND bitmasks
    pub static ref AND_BITMASK_REGEX: Regex = Regex::new(r"\(0x([a-fA-F0-9]{2}){1,32}\) & ").expect("failed to build regex");

    /// The following regex is used as a detector for AND bitmasks
    pub static ref AND_BITMASK_REGEX_2: Regex = Regex::new(r" & \(0x([a-fA-F0-9]{2}){1,32}\)").expect("failed to build regex");

    /// used to detect non-zero bytes within a word
    pub static ref NON_ZERO_BYTE_REGEX: Regex = Regex::new(r"[a-fA-F0-9][a-fA-F1-9]").expect("failed to build regex");

    /// detects a parenthesis enclosed expression
    pub static ref ENCLOSED_EXPRESSION_REGEX: Regex = Regex::new(r"\(.*\)").expect("failed to build regex");

    /// detects a memory access
    pub static ref MEMORY_ACCESS_REGEX: Regex = Regex::new(r"memory\[.*\]").expect("failed to build regex");

    /// detects a storage access
    pub static ref STORAGE_ACCESS_REGEX: Regex = Regex::new(r"storage\[.*\]").expect("failed to build regex");

    /// detects a storage access
    pub static ref TSTORE_ACCESS_REGEX: Regex = Regex::new(r"transient\[.*\]").expect("failed to build regex");

    /// detects division by 1
    pub static ref DIV_BY_ONE_REGEX: Regex = Regex::new(r" \/ 0x01(?!\d)").expect("failed to build regex");

    /// detects multiplication by 1
    pub static ref MUL_BY_ONE_REGEX: Regex = Regex::new(r"\b0x01\b\s*\*\s*| \*\s*\b0x01\b").expect("failed to build regex");

    /// memory variable regex
    pub static ref MEMORY_VAR_REGEX: Regex = Regex::new(r"^var_[a-zA-Z]{1,2}$").expect("failed to build regex");

    /// extracts commas within a certain expression, not including commas within parentheses
    pub static ref ARGS_SPLIT_REGEX: Regex = Regex::new(r",\s*(?![^()]*\))").expect("failed to build regex");

    /// used to detect compiler size checks
    pub static ref VARIABLE_SIZE_CHECK_REGEX: Regex = Regex::new(r"!?\(?0(x01)? < [a-zA-Z0-9_\[\]]+\.length\)?").expect("failed to build regex");

    /// llm postprocessing prompt
    pub static ref LLM_POSTPROCESSING_PROMPT: String =
"The following solidity code was generated by a decompiler, and is very messy and lacking variable names and comments as a result.
This solidity code may not compile either, and may include bits that are not valid solidity code.

Your task is to postprocess this decompiled code, cleaning it up and making it more readable. Specifically:
 - Add comments where you are able to infer what the code does.
 - Rename variables where you can infer what the variable is used for.
 - Remove redundant checks or lines that do not affect the overall functionality of the code.
 - Add an `@notice` to the end of the pre-existing docsting with a short summary of the function. Ensure the notice follows the indentation and spacing of the rest of the docstring.

Respond in the format ```{{code}}```. Respond only with the code after your modifications have been applied.

```{source}```".to_string();

    /// the static header for decompiled solidity contracts
    pub static ref DECOMPILED_SOURCE_HEADER_SOL: String =
"// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @title            Decompiled Contract
/// @author           Jonathan Becker <jonathan@jbecker.dev>
/// @custom:version   heimdall-rs v{}
///
/// @notice           This contract was decompiled using the heimdall-rs decompiler.
///                     It was generated directly by tracing the EVM opcodes from this contract.
///                     As a result, it may not compile or even be valid solidity code.
///                     Despite this, it should be obvious what each function does. Overall
///                     logic should have been preserved throughout decompiling.
///
/// @custom:github    You can find the open-source decompiler here:
///                       https://heimdall.rs

contract DecompiledContract {".to_string();

    /// the static header for decompiled yul contracts
    pub static ref DECOMPILED_SOURCE_HEADER_YUL: String =
"/// @title            Decompiled Contract
/// @author           Jonathan Becker <jonathan@jbecker.dev>
/// @custom:version   heimdall-rs v{}
///
/// @notice           This contract was decompiled using the heimdall-rs decompiler.
///                     It was generated directly by tracing the EVM opcodes from this contract.
///                     As a result, it may not compile or even be valid yul code.
///                     Despite this, it should be obvious what each function does. Overall
///                     logic should have been preserved throughout decompiling.
///
/// @custom:github    You can find the open-source decompiler here:
///                       https://heimdall.rs

object \"DecompiledContract\" {
object \"runtime\" {
code {

function selector() -> s {
s := div(calldataload(0), 0x100000000000000000000000000000000000000000000000000000000)
}

function castToAddress(x) -> a {
a := and(x, 0xffffffffffffffffffffffffffffffffffffffff)
}

switch selector()".to_string();

}
