@using BTCPayServer.Plugins.Wabisabi
@using BTCPayServer.Abstractions.Contracts
@using NBitcoin
@using System.Security.Claims
@using System.Web.NBitcoin
@using BTCPayServer
@using BTCPayServer.Abstractions.TagHelpers
@using BTCPayServer.Client
@using BTCPayServer.Configuration
@using BTCPayServer.Services.Invoices
@using BTCPayServer.Services.Stores
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using WalletWasabi.Backend.Controllers
@using WalletWasabi.Blockchain.Analysis
@using WalletWasabi.Wallets
@model BTCPayServer.Plugins.Wabisabi.WabisabiStoreSettings
@inject WabisabiCoordinatorClientInstanceManager WabisabiCoordinatorClientInstanceManager
@inject IScopeProvider _scopeProvider
@inject StoreRepository StoreRepository
@inject WalletProvider WalletProvider
@inject BTCPayNetworkProvider BtcPayNetworkProvider
@inject BTCPayServerOptions BtcPayServerOptions
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
@{
    var liteMode = Context.Items.TryGetValue("cjlite", out _);

    var storeId = _scopeProvider.GetCurrentStoreId();
    ViewData.SetActivePage("CoinjoinSettings", "Coinjoin", "Coinjoin settings", storeId);
    var userid = Context.User.Claims.Single(claim => claim.Type == ClaimTypes.NameIdentifier).Value;
    var anyEnabled = Model.Settings.Any(settings => settings.Enabled);
    ScriptPubKeyType? scriptType;

    var stores = (await StoreRepository.GetStoresByUserId(userid))
        .ToDictionary(s => s.Id, s => (s, s.GetDerivationSchemeSettings(PaymentMethodHandlerDictionary,"BTC")));

    stores.TryGetValue(storeId, out var thisStore);
    scriptType = thisStore.Item2?.AccountDerivation.ScriptPubKeyType();
    var selectStores =
        stores.Where(pair => pair.Key != storeId && pair.Value.Item2 is not null && pair.Value.Item2?.AccountDerivation.ScriptPubKeyType() == scriptType)
            .Select(pair => new SelectListItem(pair.Value.s.StoreName, pair.Key, Model.MixToOtherWallet == pair.Key)).Prepend(new SelectListItem("None", ""));
}


<form method="post" asp-action="UpdateWabisabiStoreSettings" asp-controller="WabisabiStore" asp-route-storeId="@storeId">


<partial name="_StatusMessage"/>
<div class="d-flex align-items-center justify-content-between mb-3">
    <h3 class="mb-0">
        <span>@ViewData["Title"]</span>
        <a href="https://docs.btcpayserver.org/Wabisabi" target="_blank" rel="noreferrer noopener" title="More information...">
            <vc:icon symbol="info"/>
        </a>
    </h3>
    <div class="d-flex align-items-center gap-1 ">
        <div class="d-flex align-items-center @(liteMode ? "d-none" : "")">
            <input asp-for="Active" type="checkbox" class="btcpay-toggle me-2"/>
            <label asp-for="Active" class="form-label mb-0 me-1"></label>
        </div>
        <button name="command" type="submit" value="save" class="btn btn-primary mt-3 mt-sm-0 @(liteMode ? "btn-lin" : "btn-secondary")">Save</button>
        <a asp-action="ListCoinjoins" asp-route-storeId="@storeId" class="btn btn-secondary mt-3 mt-sm-0 @(liteMode ? "d-none" : "")" role="button">
            Coinjoin History
        </a>
        <button type="button" class="btn btn-secondary mt-3 mt-sm-0 @(liteMode ? "d-none" : "")" permission="@Policies.CanModifyServerSettings"
                data-bs-toggle="modal" data-bs-target="#discover-prompt">
            Add Coordinator
        </button>
        <a asp-controller="WabisabiCoordinatorConfig" asp-action="UpdateWabisabiSettings" class="btn @(liteMode ? "btn-lin" : "btn-secondary")  mt-3 mt-sm-0" permission="@Policies.CanModifyServerSettings">Coordinator</a>

        @* <a class="btn btn-secondary mt-3 mt-sm-0" href="https://gist.github.com/nopara73/bb17e89d7dc9af536ca41f50f705d329" rel="noreferrer noopener" target="_blank">Enable Discreet payments - Coming soon</a> *@
    </div>
</div>
@{
    if (BtcPayServerOptions.SocksEndpoint is null)
    {
        <div class="alert alert-danger d-flex align-items-center" role="alert">
            <vc:icon symbol="warning"/>
            <span class="ms-3">TOR is not configured on this BTCPay Server instance. All communication will be over clearnet and therefore not private!</span>
        </div>
    }

    var wallet = await WalletProvider.GetWalletAsync(storeId);
    if (wallet is BTCPayWallet && !((BTCPayKeyChain) wallet.KeyChain).KeysAvailable)
    {
        <div class="alert alert-danger d-flex align-items-center" role="alert">
            <vc:icon symbol="warning"/>
            <span class="ms-3">This wallet is either not a hot wallet, or enabled in your store settings and will not be able to participate in coinjoins.</span>
        </div>
    }
}
<style>
    #blocker:hover{
        background-color: rgba(128,128,128, 0.5);
    }
     #blocker:hover h4{
     display: block !important;
         left: 0;
         position: fixed;
         width: 100%
     }
</style>

<div class="@(anyEnabled ? "" : "d-none") card card-body coordinator-settings">
@if (Model.Active && anyEnabled)
{
    <div class="position-absolute w-100 h-100 text-center rounded" id="blocker" style=" left: 0; top: 0; z-index: 1">
        <h4 class="d-none pt-4">Settings cannot be changed while active</h4>

    </div>
}
<div class="row">
    <div class="col-sm-12 col-md-6">
        <div class="form-check">
            <input class="form-check-input plebModeRadio"
                   type="radio" asp-for="PlebMode" value="true">
            <label class="form-check-label" asp-for="PlebMode">
                Pleb mode
            </label>
            <p class="text-muted">I just want to coinjoin.</p>
        </div>
    </div>
    <div class="col-sm-12 col-md-6">
        <div class="form-check">
            <input class="form-check-input plebModeRadio" asp-for="PlebMode" type="radio"value="false">
            <label class="form-check-label" asp-for="PlebMode">
                Scientist mode
            </label>
            <p class="text-muted">The world is broken and I need to be vigilant about my bitcoin practices.</p>
        </div>
    </div>
</div>
<div id="advanced" class="@(Model.PlebMode ? "d-none" : "")">
    <button type="submit" name="command" value="reset" class="btn btn-link">Reset to defaults </button>

    <div class="row">

        <div class="col-sm-12 col-md-6">
            <div class="form-group">

                <label asp-for="AnonymitySetTarget" class="form-label">Anon score target</label>
                <input type="number" class="form-control" asp-for="AnonymitySetTarget" placeholder="target anon score" min="0">

                <p class="text-muted">Scores your coinjoined utxos based on how many other utxos in the coinjoin (and other previous coinjoin rounds) had the same value.<br/> Anonset score computation is not an exact science, and when using coordinators with massive liquidity, is not that important as all rounds (past, present, future) contribute to your privacy.</p>
            </div>
        </div>
        <div class="col-sm-12 col-md-6">
            <div class="form-group  form-check">
                <label asp-for="ConsiderEntryProximity" class="form-check-label">Consider entry proximity</label>
                <input asp-for="ConsiderEntryProximity" type="checkbox" class="form-check-input"/>
                <p class="text-muted">Coins which have been mixed but are only one hop away from the original coinjoin transaction won't be considered private. This helps break linking assumptions when coins are spent.</p>
            </div>
        </div>
    </div>


    <div class="row">

        <div class="col-sm-12 col-md-6">
            <div class="form-group  ">
                <label asp-for="FeeRateMedianTimeFrameHours" class="form-label">Mining fee limits in hours</label>
                <div class="input-group">
                    <input type="number" class="form-control" asp-for="FeeRateMedianTimeFrameHours" placeholder="hours" min="0">
                    <span class="input-group-text">hours</span>
                </div>
                <p class="text-muted">Only coinjoin if the mining fee is below the median of the specified past number of hours. Set to 0 to ignore</p>
            </div>
        </div>

        <div class="col-sm-12 col-md-6">
            <div class="form-group  ">
                <label asp-for="ExplicitHighestFeeTarget" class="form-label">Highest feerate allowed</label>
                <div class="input-group">
                    <input type="number" class="form-control" asp-for="ExplicitHighestFeeTarget" placeholder="sat/b" min="1">

                    <span class="input-group-text">sat/b</span>
                </div>
                <p class="text-muted">Only coinjoin if the mining fee is below this feerate</p>
            </div>
        </div>
    </div>


    <div class="row">
        <div class="col-sm-12 col-md-6">
            <div class="form-group  ">
                <label asp-for="ConsolidationMode" class="form-check-label">Coinsolidation mode</label>
                <select asp-for="ConsolidationMode" class="form-select">
                    <option value="@ConsolidationModeType.Never">Never</option>
                    <option value="@ConsolidationModeType.Always">Always</option>
                    <option value="@ConsolidationModeType.WhenLowFee">When the mining fee is low</option>
                    <option value="@ConsolidationModeType.WhenLowFeeAndManyUTXO">When the mining fee is low and you have too many UTXOs</option>
                </select>
                <p class="text-muted">Feed as many coins to the coinjoin as possible.</p>
                <p class="text-muted">NOTE: When choosing WhenLowFeeAndManyUTXO, if you have over @BTCPayWallet.HighAmountOfCoins coins, coinjoins will happen regardless if your wallet is full private, to consolidate your wallet to a smaller utxo set.</p>
            </div>
        </div>
        <div class="col-sm-12 col-md-6">
            <div class="form-group  ">
                <label asp-for="LowFeeTarget" class="form-label">Mining low fee threshold</label>
                <div class="input-group">
                    <input type="number" class="form-control" asp-for="LowFeeTarget" placeholder="sat/b" min="1">

                    <span class="input-group-text">sat/b</span>
                </div>
                <p class="text-muted">Consider it low fees when it is below this threshold</p>
            </div>
        </div>
    </div>


    <div class="row">
        <div class="col-sm-12 col-md-6">
            <div class="form-group">

                <label asp-for="MinimumDenominationAmount" class="form-label">Minimum denomination (in sats)</label>
                <input type="number" class="form-control" asp-for="MinimumDenominationAmount" placeholder="sats" min="0">
                <p class="text-muted">Do no use any of the standard denominations below this amount (creates change (which will get remixed) but prevent tiny utxos)</p>
            </div>
        </div>
        <div class="col-sm-12 col-md-6">
            <div class="form-group">

                <label asp-for="AllowedDenominations" class="form-label">Allowed denominations (in sats)</label>
                <select asp-for="AllowedDenominations" class="form-select" multiple="multiple">
                    @foreach (var denomination in BlockchainAnalyzer.StdDenoms)
                    {
                        <option value="@denomination">@denomination sats</option>
                    }
                </select>
                <p>DO NOT USE UNLESS YOU KNOW WHAT YOU ARE DOING</p>
                <p class="text-muted">Only generate outputs of these denoms. Leave blank to ignore. Generates change. You must match other user's settings to gain any anonymity.</p>
            </div>
        </div>
    </div>
    <div class="form-group form-check">
        <label asp-for="RedCoinIsolation" class="form-check-label">Cautious coinjoin entry mode </label>
        <input asp-for="RedCoinIsolation" type="checkbox" class="form-check-input"/>
        <p class="text-muted">Only allow a single non-private coin into a coinjoin.</p>
    </div>

    <div class="row">
        <div class="col-sm-12 col-md-6">
            <div class="form-group form-check">
                <label asp-for="BatchPayments" class="form-check-label">Batch payments</label>
                <input asp-for="BatchPayments" type="checkbox" class="form-check-input"/>
                <p class="text-muted">Batch your pending payments (on-chain payouts awaiting payment) inside coinjoins.</p>
            </div>
        </div>
        <div class="col-sm-12 col-md-6">
            <div class="form-group form-check">
                <label asp-for="ParanoidPayments" class="form-check-label">Paranoid payments</label>
                <input asp-for="ParanoidPayments" type="checkbox" class="form-check-input"/>
                <p class="text-muted">Only batch payments with fully private coins.</p>
            </div>
        </div>
    </div>

    <div class="form-group">
        <label asp-for="CrossMixBetweenCoordinatorsMode" class="form-label">Mix funds between different coordinators</label>
        <select asp-for="CrossMixBetweenCoordinatorsMode" class="form-select">
            <option value="@WabisabiStoreSettings.CrossMixMode.WhenFree">Cross mix when free</option>
            <option value="@WabisabiStoreSettings.CrossMixMode.Always">Always cross mix</option>
            <option value="@WabisabiStoreSettings.CrossMixMode.Never">Never cross mix</option>
        </select>
        <p class="text-muted">Whether to allow mixed coins to be mixed within different coordinators for greater privacy (Warning: This will make your coins to lose the free remix within the same coordinator)</p>
    </div>
    <div class="form-group">
        <label asp-for="ExtraJoinProbability" class="form-label">Continuous Coinjoin</label>
        <div class="input-group">
            <input asp-for="ExtraJoinProbability" type="number" min="0" max="100" step="any" class="form-control"/>

            <span class="input-group-text">% * 0.01 </span>
        </div>
        <p class="text-muted">Percentage (100 = 1% reality) probability of joining a round even if you have no payments to batch and all coins are private, prevents timing analysis. (Warning: a high probability will quickly eat up your balance in mining fees) </p>
    </div>
    <div class="form-group ">
        <label asp-for="MixToOtherWallet" class="form-check-label">Send to other wallet</label>
        <select asp-for="MixToOtherWallet" asp-items="selectStores" class="form-select"></select>
        <p class="text-muted">Send coins that have been created in a coinjoin in a standard denomination to another wallet</p>
    </div>
    <div class="row">

        <div class="col-sm-12 col-md-6">
            <div class="list-group  form-group">
                <div class="list-group-item font-weight-bold">Only mix coins with these labels</div>
                @if (Model.InputLabelsAllowed?.Any() is not true)
                {
                    <div class="list-group-item">No label filter applied</div>
                }
                else
                {
                    @for (var xIndex = 0; xIndex < Model.InputLabelsAllowed.Count; xIndex++)
                    {
                        <div class="list-group-item">
                            <div class="input-group input-group-sm">
                                <input asp-for="InputLabelsAllowed[xIndex]" type="text" class="form-control"/>
                                <button name="command" value="include-label-remove:@Model.InputLabelsAllowed[xIndex]" type="submit" class="btn btn-secondary btn-sm">Remove</button>
                            </div>
                        </div>
                    }
                }
                <div class="list-group-item">
                    <button name="command" value="include-label-add" type="submit" class="btn btn-secondary btn-sm">Add</button>
                </div>
            </div>
        </div>
        <div class="col-sm-12 col-md-6">
            <div class="list-group  form-group">
                <div class="list-group-item font-weight-bold">Only mix coins without these labels</div>
                @if (Model.InputLabelsExcluded?.Any() is not true)
                {
                    <div class="list-group-item">No label filter applied</div>
                }
                else
                {
                    @for (var xIndex = 0; xIndex < Model.InputLabelsExcluded.Count; xIndex++)
                    {
                        <div class="list-group-item">

                            <div class="input-group input-group-sm">
                                <input asp-for="InputLabelsExcluded[xIndex]" type="text" class="form-control"/>
                                <button name="command" value="exclude-label-remove:@Model.InputLabelsExcluded[xIndex]" type="submit" class="btn btn-secondary btn-sm">Remove</button>
                            </div>
                        </div>
                    }
                }
                <div class="list-group-item">
                    <button name="command" value="exclude-label-add" type="submit" class="btn btn-secondary btn-sm">Add</button>
                </div>
            </div>
        </div>
    </div>


</div>
</div>

@for (var index = 0; index < Model.Settings.Count; index++)
{
    <input asp-for="Settings[index].Coordinator" type="hidden"/>
    var s = Model.Settings[index];

    if (!WabisabiCoordinatorClientInstanceManager.HostedServices.TryGetValue(s.Coordinator, out var coordinator))
    {
        continue;
    }
    
    var safeName = HttpUtility.UrlEncode(s.Coordinator);

    <div class="card  mt-3">
        <div class="card-header d-flex justify-content-between">
            <div>
                <div class="d-flex">

                    <h3>@coordinator.CoordinatorDisplayName</h3>
                    @if (coordinator.CoordinatorName != "local")
                    {
                        <button name="command" type="submit" value="remove-coordinator:@(coordinator.CoordinatorName)" class="btn btn-link txt-danger" permission="@Policies.CanModifyServerSettings">Remove</button>
                    }
                </div>

                <span class="text-muted">@coordinator.Coordinator</span>
                <div>
                    <div>@(!coordinator.WasabiCoordinatorStatusFetcher.Connected ? "Coordinator Status: Not connected" : "Coordinator Status: Connected")</div>

                    @if (!string.IsNullOrEmpty(coordinator.Description))
                    {
                        <p class="text-muted">@coordinator.Description</p>
                    }
                    @if (coordinator.RoundStateUpdater.AnyRound && coordinator.RoundStateUpdater.RoundStates.Any(pair => pair.Value.BlameOf == uint256.Zero))
                    {
                        var round = coordinator.RoundStateUpdater.RoundStates.Last(pair => pair.Value.BlameOf == uint256.Zero).Value;
                        var roundParameters = round.CoinjoinState.Parameters;

                        <div class="modal modal-lg fade" id="config-@safeName">
                            <div class="modal-dialog">
                                <div class="modal-content">
                                    <div class="modal-header">
                                        <h5 class="modal-title" id="exampleModalLabel">@coordinator.CoordinatorDisplayName Last round parameters </h5>
                                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                                    </div>
                                    <div class="modal-body" style="white-space: pre-line">
                                        <table class="table table-responsive my-0">

                                            <tr>
                                                <th scope="row">Fee charged</th>
                                                @{
                                                    var fee = $"{roundParameters.CoordinationFeeRate.Rate * 100}%";
                                                }
                                                <td>
                                                    @(fee)
                                                </td>
                                            </tr>
                                            <tr>
                                                <th scope="row">Allowed input amounts</th>
                                                <td>@roundParameters.AllowedInputAmounts.Min.ToDecimal(MoneyUnit.BTC) BTC - @roundParameters.AllowedInputAmounts.Max.ToDecimal(MoneyUnit.BTC) BTC</td>
                                            </tr>
                                            <tr>
                                                <th scope="row">Allowed input types</th>
                                                <td>@string.Join(", ", roundParameters.AllowedInputTypes)</td>
                                            </tr>
                                            <tr>
                                                <th scope="row">Allowed output amounts</th>
                                                <td>@roundParameters.AllowedOutputAmounts.Min.ToDecimal(MoneyUnit.BTC) BTC - @roundParameters.AllowedOutputAmounts.Max.ToDecimal(MoneyUnit.BTC) BTC</td>

                                            </tr>
                                            <tr>
                                                <th scope="row">Allowed output types</th>

                                                <td>@string.Join(", ", roundParameters.AllowedOutputTypes)</td>
                                            </tr>
                                            <tr>
                                                <th scope="row">Minimum inputs</th><td>@roundParameters.MinInputCountByRound</td>
                                            </tr>
                                            <tr>
                                                <th scope="row">Maximum inputs</th><td>@roundParameters.MaxInputCountByRound</td>
                                            </tr>
                                            <tr>
                                                <th scope="row">Maximum round registration time</th><td>@roundParameters.StandardInputRegistrationTimeout.ToString()</td>
                                            </tr>

                                        </table>
                                        <div class="alert alert-info">Please note that a coordinator can change its configuration at will. This is only a display of the last round received from them.</div>
                                    </div>
                                    <div class="modal-footer">
                                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <a class="px-2 cursor-pointer"
                           data-bs-toggle="modal" data-bs-target="#config-@safeName">
                            Coordinator Config
                        </a>
                        @if (Model.Settings[index].RoundWhenEnabled is not null && !BTCPayWallet.IsRoundOk(roundParameters, Model.Settings[index]))
                        {
                            <div class="alert alert-danger w-100 mb-0 p-1">Round fees/parameters changed. Coinjoins will not occur unless you accept the new parameters.<button class="btn btn-link alert-link p-0" name="command" type="submit" value="accept-terms:@s.Coordinator"> Accept new terms</button></div>
                        }
                    }

                    <a class="px-2 w-100 cursor-pointer"
                       data-bs-toggle="modal" data-bs-target="#terms-@safeName"
                       style="
                                            right: 0;
                                            text-align: right;
                                        ">
                        By enabling this coordinator, you agree to their terms and conditions.
                    </a>
                </div>

            </div>
            @{
                var canEnable = coordinator.WasabiCoordinatorStatusFetcher.Connected && coordinator.RoundStateUpdater.AnyRound;
            }
            <div class="form-group form-check form" data-bs-toggle="tooltip" title="@(!canEnable ? "You cannot enable this coordinator until it is connected and a round has been seen" : string.Empty)">
                @if (Model.Settings[index].RoundWhenEnabled is not null)
                {
                    <input type="hidden" asp-for="Settings[index].RoundWhenEnabled.CoordinationFeeRate"/>
                    <input type="hidden" asp-for="Settings[index].RoundWhenEnabled.MinInputCountByRound"/>
                }

                <input asp-for="Settings[index].Enabled"

                       type="checkbox" class="form-check-input form-control-lg toggle-settings"
                       data-coordinator="@s.Coordinator"
                       disabled="@(!Model.Settings[index].Enabled && !canEnable)"/>

            </div>

        </div>
        <div class="modal modal-lg fade" id="terms-@safeName">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title" id="exampleModalLabel">@coordinator.CoordinatorName Terms & Conditions </h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div class="modal-body" style="white-space: pre-line">
                        @Safe.Raw(coordinator.TermsConditions)
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                    </div>
                </div>
            </div>
        </div>

    </div>
}


</form>
@if (!liteMode)
{
    <partial name="Wabisabi/AddCoordinatorPrompt" model="@(new DiscoveredCoordinator())"/>
}


@section PageFootContent {
    <partial name="_ValidationScriptsPartial"/>
}

<script type="text/javascript">

 function handlePlebModeChange(evt){
     const isPlebMode = evt.target.value === "true";
     
     const el = document.querySelector(`#advanced`);
     if (isPlebMode){
        el.classList.add("d-none");
     }else{
     
        el.classList.remove("d-none");
     }
 }
 
  function handleCoordinatorEnabled(evt){
      let enabled = evt.target.checked;
      if (!enabled){
        
      for (const settings of document.querySelectorAll("input.toggle-settings")) {
        if (settings.checked){
            enabled = true;
            break;
      }
          }}
      const el = document.querySelector(`.coordinator-settings`);
      if (!enabled){
         el.classList.add("d-none");
      }else{      
         el.classList.remove("d-none");
      }
  }

 document.addEventListener("DOMContentLoaded", function () {
    const batchPaymentsEl = document.getElementById("BatchPayments");
    const paranoidPaymentsEl = document.getElementById("ParanoidPayments");
    const consolidationModeEl = document.getElementById("ConsolidationMode");
    const lowFeeTargetEl = document.getElementById("LowFeeTarget");
     
    
    function handle(){
            
        if (consolidationModeEl.value.startsWith("WhenLowFee")){
            lowFeeTargetEl.parentElement.parentElement.classList.remove("d-none");
        } else{ 
            lowFeeTargetEl.parentElement.parentElement.classList.add("d-none");
        }
        if (!batchPaymentsEl.checked){
            paranoidPaymentsEl.parentElement.parentElement.classList.add("d-none");
        } else{
            paranoidPaymentsEl.parentElement.parentElement.classList.remove("d-none");
           }
    }
     handle();
    batchPaymentsEl.addEventListener("change", handle);
    consolidationModeEl.addEventListener("change", handle);
     
     document.querySelectorAll("input.toggle-settings").forEach(value => value.addEventListener("change", handleCoordinatorEnabled));
            document.querySelectorAll("input.plebModeRadio").forEach(value => value.addEventListener("change", handlePlebModeChange));
        });
 

</script>