// File: contracts/MarketPlaceCommon.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.18;

/**
 * @title MarketPlaceCommon
 * @dev A base contract for handling common marketplace functionalities
 */
contract MarketPlaceCommon {
  address payable public dxs;
  address payable public supplier;
  address public owner;

  uint public minProductPrice;
  uint public maxVAT = 27;

  mapping(address => uint) public purchasedBalance;

  event ProductPurchased(address indexed buyer, uint amount);

  event BalanceWithdrawn(address indexed withdrawer, uint amount);

  event SupplierChanged(
    address indexed oldSupplier,
    address indexed newSupplier
  );

  event DXSChanged(address indexed oldDXS, address indexed newDXS);

  event MinProductPriceChanged(uint oldPrice, uint newPrice);

  event OwnershipTransferred(
    address indexed oldOwner,
    address indexed newOwner
  );

  /**
   * @dev Initialize the contract
   * @param _dxs Decentrashop's address
   * @param _supplier Supplier's address
   */
  constructor(address _dxs, address _supplier) {
    require(
      _dxs != address(0),
      'Decentrashop address cannot be the zero address.'
    );

    require(
      _supplier != address(0),
      'Supplier address cannot be the zero address.'
    );

    owner = msg.sender;
    dxs = payable(_dxs);
    supplier = payable(_supplier);
  }

  modifier onlyOwner() {
    require(msg.sender == owner, 'You are not the contract Owner.');
    _;
  }

  function setSupplier(address newSupplier) external onlyOwner {
    require(
      newSupplier != address(0),
      'Supplier address cannot be the zero address.'
    );
    address oldSupplier = supplier;
    supplier = payable(newSupplier);

    emit SupplierChanged(oldSupplier, newSupplier);
  }

  function setDXS(address newDXS) external onlyOwner {
    require(newDXS != address(0), 'DXS address cannot be the zero address.');
    address oldDXS = dxs;
    dxs = payable(newDXS);

    emit DXSChanged(oldDXS, newDXS);
  }

  function setMinProductPrice(uint newMinProductPrice) external onlyOwner {
    uint oldPrice = minProductPrice;
    minProductPrice = newMinProductPrice;

    emit MinProductPriceChanged(oldPrice, newMinProductPrice);
  }

  function transferOwnership(address newOwner) external onlyOwner {
    require(newOwner != address(0), 'New owner cannot be the zero address.');
    address oldOwner = owner;
    owner = newOwner;

    emit OwnershipTransferred(oldOwner, newOwner);
  }

  /**
   * @dev Set the maximum VAT Possible
   * @param newMaxVAT The new minimum product price
   */
  function setMaxVAT(uint newMaxVAT) external onlyOwner {
    require(newMaxVAT <= 50, 'VAT cannot be greater than 50%.');
    maxVAT = newMaxVAT;
  }

  /**
   * @dev Rectify the balance of a wallet address
   * @param walletAddress The address of the wallet
   * @param amount The new balance of the wallet
   */
  function rectifyBalance(
    address walletAddress,
    uint amount
  ) external onlyOwner {
    purchasedBalance[walletAddress] = amount;
  }

  fallback() external {
    revert('Do not send Ether directly.');
  }
}

// File: contracts/MarketPlaceFees.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.18;

import './MarketPlaceCommon.sol';

/**
 * @title MarketPlaceFees
 * @dev A contract for handling marketplace transactions and fees
 */
contract MarketPlaceFees is MarketPlaceCommon {
  /**
   * @dev Initialize the contract
   * @param _dxs Decentrashop's address
   * @param _supplier Supplier's address

   */
  constructor(
    address _dxs,
    address _supplier
  ) MarketPlaceCommon(_dxs, _supplier) {
    minProductPrice = 0.0001 ether;
  }

  /**
   * @dev Buy a product
   * Buyer sends funds and his balance is registred.
   */
  function buyProduct() external payable {
    require(msg.value > minProductPrice, 'Value sent is too low.');

    purchasedBalance[msg.sender] += msg.value;

    emit ProductPurchased(msg.sender, msg.value);
  }

  /**
   * @dev Withdraw all balances
   * Contract funds are distributed between decentrashop and the supplier.
   */
  function withdrawAllBalances() external {
    require(msg.sender == owner, 'You are not the contract Owner.');

    uint valueWithVAT = address(this).balance;
    // Calculate the percentages
    uint valueWithoutVAT = (valueWithVAT * 100) / (100 + maxVAT); //To get the value without VAT in France for instance -> 120(TTC) / 1.2 = 100(HT)
    uint dxsShare = (valueWithoutVAT * 55) / 1000; // 5.5%

    emit BalanceWithdrawn(msg.sender, address(this).balance);

    dxs.transfer(dxsShare);
    supplier.transfer(address(this).balance);
  }
}