<!-- 
    A recipient form. The .value property returns a dictionary of address, label, amount and more

{#- Usage -

    <recipient-box id=`recipient_0`  recipientId=0   title=`Recipient 1`></recipient-box>

	or via the class:
			let newRecipient = new RecipientBox();
			newRecipient.id = `recipient_${recipientId}`;
			newRecipient.recipientId = recipientId;
			newRecipient.title = `Recipient ${recipientId+1}`;
			newRecipient.addEventListener('address-input', (event) => {
				validateForm()
			})


	It exposes the events:
	  - 'remove'   # is called when the remove button is clicked
	  - 'address-input'
	  - 'unit-change'
	  - 'send-max'


	It has the attributes: ["value", "name", "id", "title", "address", "label", 
								"recipientId", "max", "step", "amount", "hiddenRemoveButton"]
			These attributes will be assigned to the appropriate html elements

	It has the properties:
	  - 'value' returns a dict with important attributes

#} 
-->

<template id="recipient-box">
	<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='output.css') }}">

	<div id="recipient" class="recipient_wrapper_item">		
		<div class="px-4 py-3 flex justify-between bg-dark-700">
			<span id='title' class="text-lg"><!-- the title comes in here--></span>		
			<img src="{{ url_for('static', filename='img/close.svg') }}" class="recipient_button recipient_remove cursor-pointer" title="Remove recipient" id="remove" data-style="float:right">
		</div>

		<div class="recipient_wrapper_inner_box px-3 py-3 space-y-3 border-l-2 border-r-2 border-dark-700">
			<div class="flex space-x-3">
				<div class="floating-wrapper grow-[3]">
					<input class="floating-input peer" type="text" id="address" name="address" value="" placeholder=" ">
					<label class="floating-label" id="addressInputLabel">Recipient Address</label>
					<qr-scanner id="address-scan" class="absolute right-2 top-2">
						<a slot="button" class="cursor-pointer">
							<img src="{{ url_for('static', filename='img/qr-code.svg') }}" data-style="width: 26px; margin: 0px;" class="svg-white">
						</a>
					</qr-scanner>
				</div>

				<div class="floating-wrapper grow-[1]">
					<input class="floating-input peer" type="text" id="label" class="address-label" name="label" value="" placeholder=" ">
					<label class="floating-label">Address Label</label>
				</div>
			</div>

			<div class="floating-wrapper">
				<input class="floating-input peer" type="number" name="amount" id="amount" min=0 step='1e-8' autocomplete="off" placeholder=" " data-cy="amount-input"> <!-- the value comes in here-->
				<label class="floating-label">Amount</label>
				<span class="btn absolute right-0.5 top-2 cursor-pointer" id="send_max">{{ _("Send Max") }}</span>
			</div>

			<div class="flex justify-between">
				<span class="text-base">Unit Selection</span>
				<span id='asset_selector' class="space-x-4 flex items-center"><!-- the assetSelector comes in here--></span>
			</div>

			<div class="hidden" id="converted_unit_container">
				<span id="converted_unit_amount">-</span> <span class="note" id="converted_unit_label"><!-- the convertedUnit comes in here--></span> <span class="note" id="converted_unit_alt"></span>
			</div>
		</div>
	<div>
</template>


<template id="liquid-asset-selector">
	<select id="amount_unit" name="amount_unit" data-style="width: 100px;" >
		<option value="btc">LBTC</option>
		<option value="sat">L-sat</option>
	{% for asset in wallet.balance.get("assets",{}).keys() | sort %}
		<option value="{{asset}}">{{asset | assetlabel}}</option>
	{% endfor %}
	</select>
</template>

<template id="bitcoin-asset-selector">
	<label class="flex items-center space-x-1">
		<input id="amount_unit_sat" type="radio" class="" name="amount_unit" value="sat" data-cy="sats-checkbox">
		<span class="text-lg">Satoshi</span>
	</label>
	<label class="flex items-center space-x-1">
		<input id="amount_unit_btc" type="radio" class="" name="amount_unit"  value="btc">
		<span class="text-lg">BTC</span>
	</label>
</template>



<script type="text/javascript">
	class RecipientBox extends HTMLElement {
		constructor() {
			super();
			
			this.internals = this.attachInternals();
			this.recipientId = null;	// MUST be set for a functioning instance

			this.buildHTML();			// created the html
			this.attachListeners();		// attaches the listeners to some html objects
		}



		// creates the entire html code (without event listeners)  from the template
		buildHTML(){
			// Create a shadow root
			this.attachShadow({
				mode: 'open'
			});

			var template_content = document.getElementById('recipient-box').content;
            let clone = template_content.cloneNode(true);

			this.amountElement = clone.getElementById('amount');
			this.addressElement = clone.getElementById('address');
			this.addressInputLabel = clone.getElementById('addressInputLabel')
			this.labelElement = clone.getElementById('label');
			this.titleElement = clone.getElementById('title'); 
			this.removeElement = clone.getElementById('remove'); 

			this.shadowRoot.appendChild(clone);
			this.addAssetSelectorToShadowRoot()			
		}



		// add the html code for the assetSelector
		addAssetSelectorToShadowRoot() { 
			// add different asset selector template for bitcoin and liquid
			{% if specter.is_liquid and wallet.balance.get("assets", {}) %}
				var template_content = document.getElementById('liquid-asset-selector').content;
				var clone = template_content.cloneNode(true);				

				this.amountUnitElement = clone.getElementById('amount_unit');
				// create custom getter and setter functions
				this.setUnit =  (newValue) => {
					this.amountUnitElement.value = newValue;
					this.updateUnitLabelAndStep();
				}
				this.getUnit =  () => {
					return this.amountUnitElement.value;
				}
			{% else %}
				var template_content = document.getElementById('bitcoin-asset-selector').content;
				var clone = template_content.cloneNode(true);				

				this.amountUnitSatElement = clone.getElementById('amount_unit_sat');
				this.amountUnitBtcElement = clone.getElementById('amount_unit_btc');
				// create custom getter and setter functions
				this.setUnit =  (newValue) => {
					this.amountUnitBtcElement.checked =  newValue == 'btc';
					this.amountUnitSatElement.checked =  newValue == 'sat';
					this.updateUnitLabelAndStep();
				}
				this.getUnit =  () => {
					return this.amountUnitBtcElement.checked  ? this.amountUnitBtcElement.value : this.amountUnitSatElement.value ;
				}
			{% endif %}


			this.shadowRoot.getElementById('asset_selector').appendChild(clone);

		} 



		// adds EventListeners 
		attachListeners(){
			// I cannot use  getElementById , but  have to use querySelectorAll, because there are multiple unit buttons,
			// that need to trigger the same event
			this.shadowRoot.querySelectorAll('[name="amount_unit"]').forEach(input => {
				input.addEventListener('change',() => {
					this.updateUnitLabelAndStep();

					this.dispatchEvent(new CustomEvent('unit-change'));
				});	
			}); 	

			this.addressElement.addEventListener('input', (e) => {
				// Resetting for the case that user inputs own address and then clears the address at once
				if (this.addressElement.value === '') {
					this.addressElement.removeAttribute('data-cy', 'address-is-mine')
					this.addressInputLabel.innerText = "Recipient Address"
				}
				else {
					this.dispatchAddressOnInput();
				}
			});
			
			this.shadowRoot.getElementById('address-scan').addEventListener('scan', event=>{
				let addr = event.detail.result;
				if(addr == null){
					return;
				}
				// remove bitcoin: stuff
				if(addr.indexOf("bitcoin:") >= 0){
					addr = addr.substr(addr.indexOf("bitcoin:")+8);
				}
				let arr = addr.split("?");
				addr = arr[0];
				this.addressElement.value = addr;
				let evt = new Event('input');
				this.addressElement.dispatchEvent(evt);
				// parse metadata like amount and message
				if(arr.length > 1){
					arr = arr[1].split("&");
					arr.forEach((e)=>{
						if(e.startsWith("amount=")){
							let val = parseFloat(e.substr(7));
							if(this.unit == 'sat'){
								val = Math.round(val*1e8);
							}
							this.amountElement.value = val;
							let evt = new Event('input');
							this.amountElement.dispatchEvent(evt);
						}
						if(e.startsWith("message=") || e.startsWith("label=")){
							this.labelElement.value = e.split("=")[1];
						}
					});
				}
			});

			
			this.shadowRoot.getElementById('send_max').addEventListener('click', event=>{
				this.dispatchSendMax()
			});			


			this.removeElement.addEventListener('click', event=>{
				this.dispatchRemove()
			});			

			this.amountElement.addEventListener('input', event=>{
				this.calculateConvertedUnit()
			});			


		}



		markAddressGreenIfMine(){
			// mark own addresses green
			this.isAddressMyOwn().then((isMine) => {
				this.markRecipient(isMine);
			});
		}

		dispatchAddressOnInput(result) {
			let address = this.addressElement.value;
			// To reduce the fetch API calls if the address is typed
			// TODO: If we have a better JS address validation, this can be useful here, too
			if (address.length >= 14) {
				this.markAddressGreenIfMine();
				this.dispatchEvent(new CustomEvent('address-input'));
			}
		}

		dispatchRemove(result) {
			this.dispatchEvent(new CustomEvent('remove'));
		}

		dispatchSendMax(result) {
			this.dispatchEvent(new CustomEvent('send-max'));
		}



		// this function together with attributeChangedCallback ensures that setting attributes directly in html 
		// like <recipient-box title='title'></div>  works.
		static get observedAttributes() {
			// define the attributes that can be defined via <recipient-box name="recipient-box" id='4'></recipient-box>	
			var attributes = ["value", "name", "id", "title", "address", "label", "unit", 
								"recipientId", "max", "step", "amount", "hiddenRemoveButton"];
			return attributes;
		}

		attributeChangedCallback(attribute, oldValue, newValue) {
			if (oldValue == newValue){return}
			if (attribute=="value"){
				this.value = newValue;
			} else if (attribute=="name"){
				this.name = newValue;
			} else if (attribute=="address"){
				this.address = newValue;
			} else if (attribute=="title"){
				this.title = newValue;
			} else if (attribute=="recipientId"){
				this.recipientId = newValue;
			} else if (attribute=="label"){
				this.label = newValue;
			} else if (attribute=="unit"){
				this.unit = newValue;
			} else if (attribute=="step"){
				this.step = newValue;
			} else if (attribute=="max"){
				this.max = newValue;
			} else if (attribute=="amount"){
				this.amount = newValue;
			} else if (attribute=="id"){
				this.id = newValue;
			} else if (attribute=="hiddenRemoveButton"){
				this.hiddenRemoveButton = newValue;
			}
			
		}



		// title
		set title(newValue){
			this.titleElement.innerText = newValue;
		}			
		get title(){
			return this.titleElement.innerText;
		}		

		// address
		set address(newValue){
			this.addressElement.value = newValue;
			this.markAddressGreenIfMine();
		}			
		get address(){
			return this.addressElement.value;
		}		

		// label
		set label(newValue){
			this.labelElement.value = newValue;
		}			
		get label(){
			return this.labelElement.value;
		}		

		// unit
		set unit(newValue){
			// this function is different for bitcoin and liquid 
			this.setUnit(newValue);
		}			
		get unit(){
			// this function is different for bitcoin and liquid 
			return this.getUnit();
		}				

		// step
		set step(newValue){
			this.amountElement.step = newValue;
		}			
		get step(){
			return parseFloat(this.amountElement.step );
		}		

		// amount
		set amount(newValue){
			this.amountElement.value = newValue;
			this.calculateConvertedUnit()
		}			
		get amount(){
			var value = parseFloat(this.amountElement.value );
			return value;
		}		


		// max
		set max(newValue){
			this.amountElement.max = newValue;
		}			
		get max(){
			return parseFloat(this.amountElement.max );
		}		




		// value
		set value(newValue) {
			// loop through all the keys and set the attributes
			for (var key in newValue) {
				this.attributeChangedCallback(key, null,  newValue[key]);
			} 
		}

		// Returns a dict with important attributes
		// the keys are in python style, because they will be later sent to the python server
		get value() {
			return {
				"unit":this.unit,
				"amount":this.amount,
				"btc_amount":this.btcAmount,
				"recipient_id":this.recipientId,
				"label":this.label,
				"address":this.address,
			}
		}

		static get properties() {
			return {
				value: {
					type: String
				}
			};
		}


		// btcAmount
		get btcAmount(){
			return (this.unit == 'sat' ? this.amount / 1e8 : this.amount);
		}		




		// hiddenRemoveButton
		set hiddenRemoveButton(newValue){
			if (!this.shadowRoot) {return }
			this.removeElement.hidden = newValue;
		}			
		get hiddenRemoveButton(){
			return this.removeElement.hidden;
		}		

		


		updateUnitLabelAndStep() {
			let unitLabelEl = this.shadowRoot.getElementById('converted_unit_label');
			if(this.unit == 'sat'){
				unitLabelEl.innerHTML = 'BTC';
			}else if(this.unit == 'btc'){
				unitLabelEl.innerHTML = 'sat';
			}else{
				unitLabelEl.innerHTML = '';
			}
			this.step = this.unit == 'sat' ? 1 : 1e-8;
			this.calculateConvertedUnit();
		}

		calculateConvertedUnit() {
			let convertedAmount = parseFloat(Number.parseFloat(this.amount / (this.unit == 'sat' ? 1e8 : 1e-8)).toFixed((this.unit == 'sat' ? 8 : 0)));
			if (isNaN(convertedAmount)) {
				convertedAmount = '-'
				this.shadowRoot.getElementById('converted_unit_container').classList.add("hidden")
			} else {
				this.shadowRoot.getElementById('converted_unit_container').classList.remove("hidden")
			}

			if(this.unit == 'sat' || this.unit == 'btc'){
				this.shadowRoot.getElementById('converted_unit_amount').innerHTML = (isNaN(convertedAmount) ? '-' : convertedAmount.toFixed(8).replace(/(\.0+|0+)$/, ''));
				{% if specter.price_check %}
					let altRate = parseFloat('{{ specter.alt_rate }}');
					let altSymbol = '{{ specter.alt_symbol }}';
					let altAmount = parseFloat((altRate * this.btcAmount).toFixed(2))
					if (!isNaN(altAmount) && (altSymbol && altRate)) {
						this.shadowRoot.getElementById('converted_unit_alt').innerHTML = '&nbsp;(' + altAmount + altSymbol + ')';
					} else {
						this.shadowRoot.getElementById('converted_unit_alt').innerHTML = '';
					}
				{% endif %}
			} else {
				this.shadowRoot.getElementById('converted_unit_amount').innerHTML = '&nbsp;';
				this.shadowRoot.getElementById('converted_unit_alt').innerHTML = '&nbsp;';
			}
			
		}



		async isAddressMyOwn() {
			let address = this.addressElement.value;
			if (!address){return;}

			let url="{{ url_for('wallets_endpoint_api.is_address_mine', wallet_alias=wallet.alias, address='this_address') }}"
			url = url.replace('this_address', address)			
					
			let response = await send_request(url, 'GET', "{{ csrf_token() }}");
			return response['is_mine'];
		}

		markRecipient(is_address_mine) {
			if (is_address_mine) {
				this.addressElement.setAttribute('data-cy', 'address-is-mine')
				this.addressInputLabel.innerText = "Own Address"
			}
			else {
				this.addressElement.removeAttribute('data-cy', 'address-is-mine')
				this.addressInputLabel.innerText = "Recipient Address"
			}
		}
	}
	customElements.define('recipient-box', RecipientBox);
</script>
