// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

//Ccreazione smart contract con standard 721 (un NFT)
//importiamo da openzeppelin il contratto standard
contract Land is ERC721 {

    //VARIABILI PUBBLICHE QUINDI ACCESSIBILI DA CHIUNQUE 
    //prezzo del contratto
    uint256 public cost = 1 ether;
    //numero massimo di contratti generabili 
    uint256 public maxSupply = 13;
    //numero totale di contratti che possediamo
    uint256 public totalSupply = 0;

    //struttura dell'edificio da acquistare
    struct Building {
        string name;
        //indirizzo del nostro proprietario
        address owner;
        int256 posX;
        int256 posY;
        int256 posZ;
        uint256 sizeX;
        uint256 sizeY;
        uint256 sizeZ;
    }

    //array di costruzioni
    Building[] public buildings;

    //viene chiamato ogni volta che distribuiamo il contratto sulla blockchain
    constructor(
        //li salviamo in memomria perchè non abbiamo necessità di riutilizzarli 
        string memory _name,
        string memory _symbol,
        uint256 _cost
    ) ERC721(_name, _symbol) {
        cost = _cost;



        buildings.push(
            Building("Palazzo Centrale", address(0x0), 0, 0, 0, 60, 60, 60)
        );

        buildings.push(
            Building("Parco Nord", address(0x0), 0, 0, -180, 60, 60, 60)
        );
        buildings.push(
            Building("Parco Ovest", address(0x0), -180, 0, 0, 60, 60, 60)
        );
        buildings.push(
            Building("Parco Sud", address(0x0), 0, 0, 180, 60, 60, 60)
        );
        buildings.push(
            Building("Parco Est", address(0x0), 180, 0, 0, 60, 60, 60)
        );
        buildings.push(
            Building("Stadio", address(0x0), 90, 0, 90, 70, 70, 70)
        );
        buildings.push(
            Building("Ristorante", address(0x0), -90, 0, 90, 70, 70, 70)
        );
        buildings.push(
            Building("Sala Giochi", address(0x0), -90, 0, -90, 70, 70, 70)
        );
        buildings.push(
            Building("Albergo", address(0x0), 90, 0, -90, 70, 70, 70)
        );
        buildings.push(
            Building("Palazzo Di Giustizia", address(0x0), 0, 0, 90, 40, 40, 40)
        );
        buildings.push(
            Building("Palazzo Reale", address(0x0), 90, 0, 0, 40, 40, 40)
        );
        buildings.push(
            Building("Palazzo Generale", address(0x0), 0, 0, -90, 40, 40, 40)
        );
        buildings.push(
            Building("Palazzo Tecnologico", address(0x0), -90, 0, 0, 40, 40, 40)
        );




    }

    //funzione per acquistare nuove land
    function mint(uint256 _id) public payable {
        uint256 supply = totalSupply;
        //condizioni da rispettare prima di acqusitare un terreno
        require(supply <= maxSupply);
        require(buildings[_id - 1].owner == address(0x0));
        //la variabile msg.value contiene il valore inviato alla nostra funzione, quindi deve essere >= al costo
        require(msg.value >= cost);
 
        // msg.sendere ci permette di accedere all'indirizzo di chi ha effettuato la chiamata
        buildings[_id - 1].owner = msg.sender;
        totalSupply = totalSupply + 1;

        //funzione di openzeppelin che gestisce l'acquisto
        _safeMint(msg.sender, _id);
    }

    //TUTTE LE FUNZIONI SONO NECESSARIE A CAUSA DELLO STANDARD
    //funzione che desfinisce il trasferimento
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
        //ovverride viene utilizzata per sovrascrivere le prorietà della funzione, difatti questa funzione è già presente in openzeppelin
    ) public override {
        require(
            //funzione che definisce se il proprietario ha accettato la transizione
            //in caso di rifiuto scatta la funzione _msgSendere() con la stringa sotto definita
            _isApprovedOrOwner(_msgSender(), tokenId),
            "ERC721: transfer caller is not owner nor approved"
        );

        // aggiornaimo il proprietario dell'edificio
        buildings[tokenId - 1].owner = to;

        _transfer(from, to, tokenId);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public override {
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "ERC721: transfer caller is not owner nor approved"
        );

        buildings[tokenId - 1].owner = to;

        _safeTransfer(from, to, tokenId, _data);
    }

    // usiamo view perchè non dobbiamo scrivere sulla blockchain ma solo leggere, risparmiamo così i costi del gas
    function getBuildings() public view returns (Building[] memory) {
        return buildings;
    }

    function getBuilding(uint256 _id) public view returns (Building memory) {
        return buildings[_id - 1];
    }
}