import logging
from pathlib import Path

from slither.core.declarations import Contract
from slither.tools.properties.addresses.address import Addresses
from slither.tools.properties.utils import write_file

logger = logging.getLogger("Slither")


def generate_solidity_properties(
    contract: Contract, type_property: str, solidity_properties: str, output_dir: Path
) -> Path:
    solidity_import = 'import "./interfaces.sol";\n'
    solidity_import += f'import "../{contract.source_mapping.filename.short}";'

    test_contract_name = f"Properties{contract.name}{type_property}"

    solidity_content = (
        f"{solidity_import}\ncontract {test_contract_name} is CryticInterface,{contract.name}"
    )
    solidity_content += f"{{\n\n{solidity_properties}\n}}\n"

    filename = f"{test_contract_name}.sol"
    write_file(output_dir, filename, solidity_content)

    return Path(filename)


def generate_test_contract(
    contract: Contract,
    type_property: str,
    output_dir: Path,
    property_file: Path,
    initialization_recommendation: str,
) -> tuple[str, str]:
    test_contract_name = f"Test{contract.name}{type_property}"
    properties_name = f"Properties{contract.name}{type_property}"

    content = ""
    content += f'import "./{property_file}";\n'
    content += f"contract {test_contract_name} is {properties_name} {{\n"
    content += "\tconstructor() public{\n"
    content += "\t\t// Existing addresses:\n"
    content += "\t\t// - crytic_owner: If the contract has an owner, it must be crytic_owner\n"
    content += "\t\t// - crytic_user: Legitimate user\n"
    content += "\t\t// - crytic_attacker: Attacker\n"
    content += "\t\t// \n"
    content += initialization_recommendation
    content += "\t\t// \n"
    content += "\t\t// \n"
    content += "\t\t// Update the following if totalSupply and balanceOf are external functions or state variables:\n\n"
    content += "\t\tinitialTotalSupply = totalSupply();\n"
    content += "\t\tinitialBalance_owner = balanceOf(crytic_owner);\n"
    content += "\t\tinitialBalance_user = balanceOf(crytic_user);\n"
    content += "\t\tinitialBalance_attacker = balanceOf(crytic_attacker);\n"

    content += "\t}\n}\n"

    filename = f"{test_contract_name}.sol"
    write_file(output_dir, filename, content, allow_overwrite=False)

    return filename, test_contract_name


def generate_solidity_interface(output_dir: Path, addresses: Addresses):
    content = f"""
contract CryticInterface{{
    address internal crytic_owner = address({addresses.owner});
    address internal crytic_user = address({addresses.user});
    address internal crytic_attacker = address({addresses.attacker});
    uint internal initialTotalSupply;
    uint internal initialBalance_owner;
    uint internal initialBalance_user;
    uint internal initialBalance_attacker;
}}"""

    # Static file, we discard if it exists as it should never change
    write_file(output_dir, "interfaces.sol", content, discard_if_exist=True)
