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

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./VerifySignature.sol";

error FunctionNotSupported();
error SignatureNotValid();
error SignatureAlreadyUsed();
error ClaimNotOpen();

/*
                         %@@@@*  @@@  *#####
                   &@@@@@@@@ ,@@@@@@@@@  #########
              ,@@@@@@@@  #                  %. @@@@@@@
           &@@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@ .@@@@@@@@
         @@@@@@@@@@@. @@@@@@@@@@@@ @@@@@@@@@@@@@  @@@@@@@@@@
       ####       @  @@@@@@@@@@@@@ @@@@@@@@@@@@@@.       .&@@@
     ########. @@@@@@@@@@ @@@@@%#///#%@@@@@@ @@@@@@@@@@@  @@@@@.
    ########  @@@@@@@@@@  @@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@. @@@@@@
   ######### @@@@@@@@@@@ &@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@  @@@@@@
  %@@(       ,@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@,      &@
  @@@# @@@@@@@@@@@@ ,#####*                 . ,@@@@  %@@@@@@@@@@@@@@/
  @@@  @@@@@@@@@@@@ ##############  @@@@@@@@@@@@ ,@@@@.   @@@&  @@@@@@..#
  @@@ &@@@@@@@@@@@@ ##############  @@@@@@@@@@ @@@@@@@@@@@&   @@@@@@@@ #####
  @@@ @@@@@@@@@@@@@ ##############  @@@@@@@@ *@@@@@@@@@@  @@@. @@@@@@ ########
  @@        %@@@@@@ ##############  @@@@@@@ @@@@@@@@@@@ @@@@@@@ @@@&@ ####### /
  &&@@@@@  @@@@@@@@@@&*                    @@@@@@@@@@# @@@@@@@  &&&&&&& ##  @@@
  &&&&&@@  @@@@@@@@@@@@* @@@@@@@@@@@@@@@@* @@@    .@% @@@@@@ &&&&&&&&&&& @@@@@@
  @&&&&&&  @@@@@@@@@@@@* @@@@@@@@@@@@@@@@ @@@@@@@@@@ @@@    &&&&&&&&&&&&& @@@@@
      &&&  &@@@@@@@@@@@* @@@@@@@@@@@@@@@@ @@@@@@@@@ @@@@@@    . #&&&&&&&& @@@@/
   (((  &&       /@@@@@* @@@@@@@@@@@@@@@,.@@@@@@@@@ @@@@@& &&&&& &&&&&&     @@@
   (((* &&&&&&&&&/ @@@@@@@@@@@@@@@ @@@@@ .   .@@@@@ @@@@@  &&&&& &&&&&&&& @@@@@
   (((( &&&&&&&&&/ &&&@@@@@@@@@@@@ @@@@@  ######### %@@@@  &&&&& &&&&&&&& @@@@@
     (( &&&&&&&&&/ &&&&&&&@@@@@@@@ @@@@@% ######### @@@@@%          &&&&& @@@.
           .&&&&&/ &&&&&&&&&&&&&&@ @@@@@@ ######### @@@@@@
                                           ######## @@@@@@
 * @notice Implementation of a "Soulbound Token" to mark community members. 
 * This is an ERC1155 NFT with modification to remove transferability.
 */

contract penguPins is ERC1155, VerifySignature {
    using Strings for uint256;

    mapping(uint256 => bool) nonceUsed;

    bool public claimPaused = true;

    string private baseURI;
    string private baseURISuffix;
    
    constructor(string memory _base, string memory _suffix) 
        ERC1155("")
        VerifySignature("penguPins-v1", msg.sender)
    {
        baseURI = _base; 
        baseURISuffix = _suffix;
    }

    function airdropPenguPin(
        uint256 id,
        address [] calldata holders
    ) external onlyOwner {
        for(uint i = 0; i < holders.length; i++){
            _mint(holders[i], id, 1, "");
        }
    }

    function claimPenguPinToWallet(
        address receiverWallet,
        uint256 id,
        uint256 nonce,
        bytes memory signature
    ) external {
        if(claimPaused) revert ClaimNotOpen();
        if(!_verify(receiverWallet, id, nonce, signature)) revert SignatureNotValid();
        if(nonceUsed[nonce]) revert SignatureAlreadyUsed();

        nonceUsed[nonce] = true;
        _mint(receiverWallet, id, 1, "");
    }

    function burnTruePengu(uint256 id) external {
        _burn(msg.sender, id, 1);
    }

    function adminBurnPenguPin(address holder, uint256 id) external onlyOwner {
        _burn(holder, id, 1);
    }

    function uri(uint256 id) public view override returns (string memory) {
        return string(abi.encodePacked(baseURI, id.toString(), baseURISuffix));
    }

    function setURI(string calldata _base, string calldata _suffix) external onlyOwner {
        baseURI = _base;
        baseURISuffix = _suffix;
    }

    function pause() external onlyOwner {
        claimPaused = true;
    }

    function unpause() external onlyOwner {
        claimPaused = false;
    }

    /*
     * All functions having to do with the transfer of the NFT's have been overridden.
     * Although the approval functions don't need to be overridden, there is no use 
     * for them, so I am overriding to save users gas in case they try and execute them.
     */
    function setApprovalForAll(
        address,
        bool
    ) public pure override {
        revert FunctionNotSupported();
    }

    function safeTransferFrom(
        address,
        address,
        uint256,
        uint256,
        bytes memory
    ) public pure override {
        revert FunctionNotSupported();
    }

    function safeBatchTransferFrom(
        address,
        address,
        uint256[] memory,
        uint256[] memory,
        bytes memory
    ) public pure override {
        revert FunctionNotSupported();
    }
}
[{"inputs":[{"internalType":"string","name":"_base","type":"string"},{"internalType":"string","name":"_suffix","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ClaimNotOpen","type":"error"},{"inputs":[],"name":"FunctionNotSupported","type":"error"},{"inputs":[],"name":"SignatureAlreadyUsed","type":"error"},{"inputs":[],"name":"SignatureNotValid","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"adminBurnPenguPin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address[]","name":"holders","type":"address[]"}],"name":"airdropPenguPin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"burnTruePengu","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiverWallet","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"claimPenguPinToWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bool","name":"","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"_base","type":"string"},{"internalType":"string","name":"_suffix","type":"string"}],"name":"setURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"signVersion_","type":"string"}],"name":"updateSignVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signerWallet_","type":"address"}],"name":"updateSignerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]