// SPDX-License-Identifier: GPL-3.0-or-later

// This file is part of the http://github.com/aaronbloomfield/ccc repoistory,
// and is released under the GPL 3.0 license.

pragma solidity ^0.8.33;

import "./IDebts.sol";

contract Debts is IDebts {

	/*
	// Imported from the interface:

	// holds in the necessary information about each alias / entry
	struct Entry {
		uint id;			// the index in the 'entries' mapping
		string thealias;	// their string alias
		string name;		// their string name
		address addr;		// their account address
		int balance;		// how much they owe (if negative) or are owed (if positive)
	}

	// allow notification when a debt is entered
	event paidEvent(string towho, int amount);

	// allow notification when an alias is entered
	event aliasAddedEvent(string thealias, string name);
	*/

	// holds all the alias entry structs from above
	mapping (uint => Entry) public override entries;

	// holds true if that account address has an entry in 'entries'
	mapping (address => bool) public override addressHasEntry;

	// holds true if that alias has an entry in 'entries'
	mapping (string => bool) public override aliasHasEntry;

	// given an alias, this will give the index into the 'entries' array for that alias
	mapping (string => uint) public override findByAlias;

	// given an account address, this will give the index into the 'entries' array for that account address
	mapping (address => uint) public override findByAddress;

	// how many alias exist in the 'entries' mapping
	uint public override num_entries;


	// we don't have to do much here
	constructor() {
	}


	function addAlias (string memory _alias, string memory _name) virtual override public {
		// ensure that the alias name does not already exist
		require(!aliasHasEntry[_alias], "string entry name already exists");
		// ensure that the sender doesn't already have an alias
		require(!addressHasEntry[msg.sender], "your address already has an alias");
		// add an entry in the mapping of whether that string alias exists
		aliasHasEntry[_alias] = true;
		// add an entry in the mapping of whether a given account address has an alias
		addressHasEntry[msg.sender] = true;
		// add an entry in the mapping from alias strings to alias indices
		findByAlias[_alias] = num_entries;
		// add an entry in the mapping from account addresses to alias indices
		findByAddress[msg.sender] = num_entries;
		// add the alias entry itself
		entries[num_entries] = Entry(num_entries,_alias,_name,msg.sender,0);
		// increment the number of aliases so far
		num_entries++;
		// emit the event
		emit aliasAddedEvent(_alias,_name);
	}


	function payToAlias (string memory _alias, int amount) virtual override public {
		// limit amounts from -100 to +100
		require (amount >= -100 && amount <= 100, "amounts must be between -100 and 100");
		// amount cannot be zero
		require (amount != 0, "amount cannot be zero");
		// ensure that the caller has an alias
		require(addressHasEntry[msg.sender], "your address does not have an alias");
		// ensure that the 'to' has an alias entry
		require(aliasHasEntry[_alias], "string entry name does not exist");
		// get the alias index of who it's from, as we know they already exist
		uint from = findByAddress[msg.sender];
		// get who it's to as we know they already exist
		uint to = findByAlias[_alias];
		// one cannot enter a debt to themselves
		require(entries[to].addr!=msg.sender, "you cannot enter a debt to yourself");
		// adjust amounts on both ends
		entries[from].balance += amount;
		entries[to].balance -= amount;
		// emit the event
		emit paidEvent(_alias,amount);
	}


	function supportsInterface(bytes4 interfaceId) external override pure returns (bool) {
		return interfaceId == type(IDebts).interfaceId || interfaceId == 0x01ffc9a7;
	}

}