<template id="addresses-table">
    {% set supports_qr_code_verify = [] %}
    {% for device in wallet.devices if device.qr_code_support_verify %}
        {% set supports_qr_code_verify = supports_qr_code_verify.append(device) %}
    {% endfor %}
    {% set supports_hwi = [] %}
    {% set supports_hwi_multisig_display_address = [] %}
    {% for device in wallet.devices if device.supports_hwi_multisig_display_address %}
        {% set supports_hwi_multisig_display_address = supports_hwi_multisig_display_address.append(device) %}
    {% endfor %}
    {% for device in wallet.devices if device.hwi_support %}
        {% set supports_hwi = supports_hwi.append(device) %}
    {% endfor %}
	  <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='output.css') }}">
    <style>
        .addresses-table {
            display: table;
        }

        address-row {
            display: contents;
        }

        input::-webkit-outer-spin-button,
        input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }

        /* Firefox */
        input[type=number] {
            -moz-appearance: textfield;
        }

        .up-arrow {
            width: 0;
            height: 0;
            border: solid 5px transparent;
            border-bottom: solid 7px #fff;
            border-top-width: 0;
            float: right;
            margin-top: 7px;
        }

        .down-arrow {
            width: 0;
            height: 0;
            border: solid 5px transparent;
            border-top: solid 7px #fff;
            border-bottom-width: 0;
            float: right;
            margin-top: 7px;
        }
    </style>

    <div id="export-container" class="space-y-3 mb-8 max-w-[700px] m-auto hidden">
        <h3>{{ _("Export addresses to CSV") }}</h3>
        <div class="flex items-center">
            <input type="checkbox" class="only-current-type-checkbox" checked>
            <label class="switch-text"></label>
        </div>
        <a class="button text-white bg-accent" id="export" download>{{ _("Export") }}</a>
    </div>

    <nav class="text-center text-dark-200 border-b border-dark-600 flex justify-between items-center">
        <ul class="flex flex-wrap -mb-px self-end">
            <li aria-checked="true" class="mr-2 py-2 border-b-2 border-transparent aria-checked:text-link aria-checked:border-b-2 aria-checked:border-link" id="">
                <button type="button" id="receive-addresses-view-btn" class="text-lg inline-block py-1 px-3 hover:text-white rounded-lg hover:bg-dark-700">
                    {{ _("Receive Addresses") }}
                </button>
            </li>
            <li aria-checked="false" class="mr-2 py-2 border-b-2 border-transparent aria-checked:text-link aria-checked:border-b-2 aria-checked:border-link" id="">
                <button type="button" id="change-addresses-view-btn" class="text-lg inline-block py-1 px-3 hover:text-white rounded-lg hover:bg-dark-700">
                    {{ _("Change Addresses") }}
                </button>
            </li>
        </ul>

        <div class="flex items-center select-none">
            {% include "includes/page-limit-select.html" %}

            <div id="export-btn" class="ml-4 hover:bg-dark-700 rounded-lg py-2 px-3">
                Export
            </div>
        </div>
    </nav>

    <table class="addresses-table">
        <thead>
            <tr>
                <th value="index" class="index-header">
                    {{ _("Index") }}
                    <div class="index-arrow down-arrow"></div>
                </th>
                <th value="address" class="address-header">{{ _("Address") }}<div class="address-arrow"></div>
                </th>
                <th value="label" class="label-header optional">{{ _("Label") }}<div class="label-arrow">
                </th>
                <th value="used" class="used-header optional">{{ _("Used") }}<div class="used-arrow">
                </th>
                <th value="utxo" class="utxo-header optional">UTXO<div class="utxo-arrow">
                </th>
                <th value="amount" class="amount-header optional">{{ _("Amount") }}<div class="amount-arrow">
                </th>
                {% if supports_hwi != [] and (supports_hwi_multisig_display_address != [] or not wallet.is_multisig) %}
                  <th class="optional"></th>
                {% endif %}
            </tr>
        </thead>

        <tr class="empty">
            <td></td>
            <td>{{ _("Fetching addresses...") }}</td>
            <td class="optional"></td>
            <td class="optional"></td>
            <td class="optional"></td>
            <td class="optional"></td>
            {% if supports_hwi != [] and (supports_hwi_multisig_display_address != [] or not wallet.is_multisig) %}
                <th class="optional"></th>
            {% endif %}
            <td></td>
        </tr>

        <tbody class="addr-tbody">
        </tbody>
    </table>
    <div class="flex justify-center w-full mt-3">
        <div id="pagination-container" class="flex items-center mx-4 space-x-2">
            <a id="pagination-back" class="hidden cursor-pointer w-6">←</a>
            <span>{{ _("Page") }}</span>
            <input id="pagination-idx" class="text-center max-w-[40px] block max-h-[40px] mx-2" type="number" step="1" min="1" value="1"></input>
            <div id="pagination-counter" class="block whitespace-nowrap"></div>
            <a id="pagination-next" class="hidden cursor-pointer w-6">→</a>
        </div>
    </div>
</template>

<script type="text/javascript">
    /**
     * Custom element for showing a table of addresses.
     * Can be configured to show:
     *  - The receive addresses of a wallet (set attribute `type` to "receive" and `wallet` to the wallet's alias)
     *  - The change addresses of a wallet (set attribute `type` to "change" and `wallet` to the wallet's alias)
     * It uses Specter's API to fetch addresses every time the user changes its parameters.
     * These parameters are configured using components included in this table element:
     *  - Tabs for switching between Receive addresses (`type="receive"`) and Change addresses (`type="change"`)
     *  - Sorting addresses by any column (ascending or descending)
     *  - Configuring limit for addresses displayed per page
     *  - Pagination, jumping between pages and showing the total pages count
     *  - Export - export the all addresses or only receive or change addresses depending on the currently active tab as CSV
     *
     * The table also supports:
     *  - Showing amounts in either BTC or sats (set attribute `btc-unit` to either "btc" or "sat")
     *  - Showing prices next to the amounts (set attribute `price` to the BTC price and symbol to the symbol of the currency you're pricing at)
     */
    class AddressTableElement extends HTMLElement {
        constructor() {
            super();
            // Create a shadow root
            var shadow = this.attachShadow({ mode: 'open' });
            var style = document.getElementById('addresses-table').content;
            var clone = style.cloneNode(true);
            this.el = clone.querySelector(".addresses-table");
            this.tbody = clone.querySelector(".addr-tbody");

            // Empty row element
            this.emptyRow = clone.querySelector(".empty");

            // Tabs (Receive Addresses/ Change Addresses)
            this.receiveAddressesViewBtn = clone.querySelector("#receive-addresses-view-btn");
            this.changeAddressesViewBtn = clone.querySelector("#change-addresses-view-btn");

            // Pagination
            this.paginationNext = clone.querySelector("#pagination-next");
            this.paginationBack = clone.querySelector("#pagination-back");
            this.paginationContainer = clone.querySelector("#pagination-container");
            this.paginationCounter = clone.querySelector("#pagination-counter");
            this.paginationIdxInput = clone.querySelector("#pagination-idx");
            this.pageLimitSelect = clone.querySelector("#page-limit-select");

            // Sorting headers and arrows
            this.indexHeader = clone.querySelector(".index-header");
            this.addressHeader = clone.querySelector(".address-header");
            this.labelHeader = clone.querySelector(".label-header");
            this.usedHeader = clone.querySelector(".used-header");
            this.utxoHeader = clone.querySelector(".utxo-header");
            this.amountHeader = clone.querySelector(".amount-header");
            this.indexHeader = clone.querySelector(".index-header");
            this.indexArrow = clone.querySelector(".index-arrow");
            this.addressArrow = clone.querySelector(".address-arrow");
            this.labelArrow = clone.querySelector(".label-arrow");
            this.usedArrow = clone.querySelector(".used-arrow");
            this.utxoArrow = clone.querySelector(".utxo-arrow");
            this.amountArrow = clone.querySelector(".amount-arrow");

            // Export button
            this.exportBtn = clone.querySelector("#export-btn");
            this.exportContainer = clone.querySelector("#export-container");
            this.export = clone.querySelector("#export");
            this.switchText = clone.querySelector(".switch-text");
            this.onlyCurrentTypeSwitch = clone.querySelector(".only-current-type-checkbox");

            // Setup tabs switching
            this.receiveAddressesViewBtn.onclick = () => {
                this.changeAddressesViewBtn.parentElement.setAttribute("aria-checked", false);
                this.receiveAddressesViewBtn.parentElement.setAttribute("aria-checked", true);
                this.setAttribute("type", "receive");
            }

            this.changeAddressesViewBtn.onclick = () => {
                this.changeAddressesViewBtn.parentElement.setAttribute("aria-checked", true);
                this.receiveAddressesViewBtn.parentElement.setAttribute("aria-checked", false);
                this.setAttribute("type", "change");
            }

            // Init call id to avoid fetch returning after another one triggered
            this.callId = 0

            // Initialize default sort, search, limit and page parameters
            this.idx = 0;
            this.limit = 50;
            this.search = "";
            this.sortby = "index";
            this.sortdir = "asc";
            this.pageCount = 1;

            // Next page action
            this.paginationNext.onclick = () => {
                this.idx++;
                this.fetchAddressesItems();
            }

            // Previous page action
            this.paginationBack.onclick = () => {
                this.idx--;
                this.fetchAddressesItems();
            }

            // Listen to changes in page number selection input
            this.paginationIdxInput.onchange = () => {
                let newIdx = parseInt(this.paginationIdxInput.value);
                if (isNaN(newIdx) || (newIdx < 1 || newIdx > this.pageCount)) {
                    this.paginationIdxInput.value = this.idx + 1;
                    return;
                }
                this.idx = newIdx - 1;
                this.fetchAddressesItems();
            }

            // Listen to changes in page limit
            this.pageLimitSelect.onchange = () => {
                this.limit = this.pageLimitSelect.value;
                this.fetchAddressesItems();
            }

            // Setup sorting functionality for each column of the table header
            let sortHeaders = [
                this.indexHeader,
                this.addressHeader,
                this.labelHeader,
                this.usedHeader,
                this.utxoHeader,
                this.amountHeader,
                this.indexHeader
            ];

            for (let header of sortHeaders) {
                header.onclick = () => {
                    if (header.classList.toString().indexOf(this.sortby) != -1) {
                        // flip direction
                        this.el.querySelector(`.${this.sortby}-arrow`).classList.remove(this.sortdir == 'asc' ? 'down-arrow' : 'up-arrow');
                        this.el.querySelector(`.${this.sortby}-arrow`).classList.add(this.sortdir == 'asc' ? 'up-arrow' : 'down-arrow');
                        this.sortdir = this.sortdir == 'asc' ? 'desc' : 'asc';
                        this.export.href = this.export.href.split('?')[0] + `?onlyCurrentType=${this.onlyCurrentTypeSwitch.checked}&addressType=${this.listType}&sortby=${this.sortby}&sortdir=${this.sortdir}`;
                    } else {
                        sortHeaders.forEach(el => {
                            let existingArrow = el.querySelector(`.${this.sortby}-arrow`)
                            if (existingArrow) {
                                existingArrow.classList.remove('up-arrow');
                                existingArrow.classList.remove('down-arrow');
                            }
                        });
                        this.sortby = header.getAttribute('value');
                        this.el.querySelector(`.${this.sortby}-arrow`).classList.add(this.sortdir == 'asc' ? 'down-arrow' : 'up-arrow');
                        this.export.href = this.export.href.split('?')[0] + `?onlyCurrentType=${this.onlyCurrentTypeSwitch.checked}&addressType=${this.listType}&sortby=${this.sortby}&sortdir=${this.sortdir}`;
                    }

                    this.fetchAddressesItems();
                }
            }

            // Export data
            this.exportBtn.onclick = () => {
                if (this.exportBtn.innerText == 'Done') {
                    this.exportContainer.classList.add('hidden');
                    this.exportBtn.innerText = 'Export';
                } else {
                    this.exportContainer.classList.remove('hidden');
                    this.exportBtn.innerText = 'Done';
                }
            }

            this.export.onclick = () => {
                this.exportContainer.classList.add('hidden');
                this.exportBtn.innerText = 'Export';
            }

            // Export all addresses or only currently active tab addresses switch toggle
            this.onlyCurrentTypeSwitch.onchange = () => {
                this.export.href = this.export.href.split('?')[0] + `?onlyCurrentType=${this.onlyCurrentTypeSwitch.checked}&addressType=${this.listType}&sortby=${this.sortby}&sortdir=${this.sortdir}`;
            }

            // Attach the created element to the shadow dom
            shadow.appendChild(clone);
        }

        static get observedAttributes() {
            return ['type', 'wallet', 'btc-unit', 'price', 'symbol', 'hide-sensitive-info'];
        }

        /**
         * Listens to changes on the following attributes:
         * - btc-unit: Bitcoin unit to display amounts with. Either "btc" or "sat"
         * - price: BTC price for price calculations
         * - symbol: Currency symbol for price calculations
         * - type: Addresses list type to load. Either "receive" or "change"
         * - hide-sensitive-info: Mask user sensitive info. Either "true" or "false"
         * - wallet: The wallet alias
        */
        attributeChangedCallback(attrName, oldValue, newValue) {

            if (
                this.listType != this.getAttribute('type') ||
                this.wallet != this.getAttribute('wallet') ||
                this.btcUnit != this.getAttribute('btc-unit') ||
                this.price != this.getAttribute('price') ||
                this.symbol != this.getAttribute('symbol') ||
                this.hideSensitiveInfo != this.getAttribute('hide-sensitive-info')
            ) {
                this.listType = this.getAttribute('type');
                this.wallet = this.getAttribute('wallet');
                this.btcUnit = this.getAttribute('btc-unit');
                this.price = this.getAttribute('price');
                this.symbol = this.getAttribute('symbol');
                this.hideSensitiveInfo = this.getAttribute('hide-sensitive-info') == 'true';

                if (!this.listType) {
                    return
                }
                this.fetchAddressesItems();
            }
        }

        /**
         * Fetches addresses list from the Specter API and loads the result into AddressRowElement
        */
        async fetchAddressesItems() {
            this.callId++;
            // Clean up from existing addresses list
            this.emptyRow.children[1].innerText = '{{ _("Fetching addresses...") }}';
            this.emptyRow.classList.remove('hidden');
            this.tbody.querySelectorAll('address-row').forEach((row) => { row.remove() });
            if (!this.listType) {
                this.emptyRow.children[1].innerText = '{{ _("Failed to fetch addresses...") }}';
                return
            }

            const url = `{{ url_for('wallets_endpoint_api.addresses_list', wallet_alias='WALLET_ALIAS') }}`.replace("WALLET_ALIAS", this.wallet);

            this.export.href = `{{ url_for('wallets_endpoint_api.addresses_list_csv', wallet_alias='WALLET_ALIAS') }}`.replace("WALLET_ALIAS", this.wallet);
            this.export.href += `?onlyCurrentType=${this.onlyCurrentTypeSwitch.checked}&addressType=${this.listType}&sortby=${this.sortby}&sortdir=${this.sortdir}`;

            if (this.listType == "receive") {
                this.switchText.innerText = '{{ _("Only receive addresses") }}: '
            } else if (this.listType == "change") {
                this.switchText.innerText = '{{ _("Only change addresses") }}: '
            } else {
                this.switchText.innerText = "";
            }

            // Prepare form data with all relevant parameters
            var formData = new FormData();
            formData.append('idx', this.idx);
            formData.append('limit', this.limit);
            formData.append('addressType', this.listType);
            formData.append('sortby', this.sortby);
            formData.append('sortdir', this.sortdir);
            formData.append('csrf_token', '{{ csrf_token() }}');
            try {
                let callId = this.callId;
                const response = await fetch(
                    url,
                    {
                        method: 'POST',
                        body: formData
                    }
                );

                if (callId != this.callId) {
                    return;
                }
                if (response.status != 200) {
                    showError(await response.text());
                    return;
                }
                const jsonResponse = await response.json();

                if ("addressesList" in jsonResponse) {
                    // Populate the table with AddressRowElement objects using the fetched address list
                    if (jsonResponse.addressesList) {
                        let addressesList = JSON.parse(jsonResponse.addressesList);

                        for (let addr of addressesList) {
                            // Address data is embedded into each row as stringified JSON in the "data-address" attr.
                            let addrRow = document.createRange().createContextualFragment(`
                            <address-row
                                data-verify-qr="{{ supports_qr_code_verify != [] }}"
                                data-verify-hwi="{{ supports_hwi != [] and (supports_hwi_multisig_display_address != [] or not wallet.is_multisig) }}"
                                data-btc-unit="${this.btcUnit ? this.btcUnit : 'btc'}"
                                data-price="${this.price ? this.price : 0}"
                                data-symbol="${this.symbol ? this.symbol : ''}"
                                data-address='${JSON.stringify(addr).replace(/[\(]/g, "&lpar;").replace(/[\)]/g, "&rpar;").replace(/[\/]/g, "&sol;").replace(/[\']/g, "&apos;")}'
                                data-hide-sensitive-info="${this.hideSensitiveInfo}"
                                data-wallet="${this.wallet}">
                            </address-row>`);

                            this.tbody.append(addrRow);
                        }

                        // Pagination
                        this.pageCount = jsonResponse.pageCount;

                        // Show empty row if no addresses found
                        if (this.pageCount == 0 || addressesList.length == 0) {
                            this.emptyRow.classList.remove('hidden');
                            this.emptyRow.children[1].innerText = '{{ _("No addresses found...") }}';
                            this.pageCount = 1;
                        } else {
                            this.emptyRow.classList.add('hidden');
                        }

                        // If index is greater than the pages count fetch again for the last page
                        if (this.idx >= this.pageCount) {
                            this.idx = this.pageCount - 1;
                            this.fetchAddressesItems()
                        }

                        this.paginationIdxInput.value = this.idx + 1;

                        // If there are multiple pages show the pagination bar
                        if (this.pageCount > 1) {
                            this.paginationContainer.classList.remove('hidden');
                            this.paginationCounter.innerText = `of ${this.pageCount}`;
                            this.paginationIdxInput.max = this.pageCount;
                        } else {
                            this.paginationContainer.classList.add('hidden');
                        }

                        // Disable pagination back button if on the first page
                        if (this.idx == 0) {
                            this.paginationBack.classList.add('hidden');
                        } else {
                            this.paginationBack.classList.remove('hidden');
                        }

                        // Disable pagination next button if on the last page
                        if (this.idx + 1 == this.pageCount) {
                            this.paginationNext.classList.add('hidden');
                        } else {
                            this.paginationNext.classList.remove('hidden');
                        }
                    }
                    return;
                }
                showError(`{{ _("Failed to fetch addresses list") }}`)
            } catch (e) {
                console.log("Caught error: ", e);
                showError(`{{ _("Failed to fetch addresses list") }}: ${e}`);
            }

        }

    }

    /**
     * Shows a <address-data> element popup for specified address.
     * @param address - Address data to show.
     * @param wallet - The wallet alias of the wallet the address belongs to.
    */
    function showAddressData(amount, amountPrice, addressData, wallet) {
        if (wallet) {
            let addressDataPopup = document.getElementById('address-popup');
            addressDataPopup.innerHTML = `
            <address-data
                data-verify-qr="{{ supports_qr_code_verify != [] }}"
                data-verify-hwi="{{ supports_hwi != [] and (supports_hwi_multisig_display_address != [] or not wallet.is_multisig) }}"
                data-used="${addressData.used}"
                data-utxo="${addressData.utxo}"
                data-amount="${amount}"
                data-amount-price="${amountPrice}"
                data-address="${addressData.address}"
                data-service-id="${addressData.service_id}"
                data-label="${addressData.label}"
                data-address-wallet="${wallet}"
            />`;
            showPageOverlay('address-popup', null, 'start');
        } else {
            copyText(address, `{{ _("Copied address") }}: ${ address }`);
        }
    }
    customElements.define('addresses-table', AddressTableElement);
</script>
