using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using AutoBidder.Models;
using AutoBidder.Utilities;
namespace AutoBidder.Dialogs
{
///
/// Sceglie cosa considerare incompleto nello storico e lo toglie.
///
/// Il conto si aggiorna a ogni spunta, prima di toccare qualunque cosa: una
/// pulizia è irreversibile, e l'unico modo di renderla una decisione informata è mostrare
/// quante righe cadrebbero e per quale motivo mentre si sceglie. La copia di sicurezza
/// prima di scrivere è la seconda rete: le statistiche sono mesi di raccolta che nessun
/// pulsante ha il diritto di far sparire per un clic distratto.
///
public partial class StatsCleanupDialog : Window
{
private readonly List _records;
public StatsCleanupDialog(List records)
{
InitializeComponent();
_records = records ?? new List();
Loaded += (_, _) => Refresh();
}
/// Righe rimosse, dopo la conferma. 0 se l'utente ha annullato.
public int RemovedCount { get; private set; }
/// Dove è finita la copia di sicurezza.
public string? BackupPath { get; private set; }
private StatsMaintenance.CleanupOptions ReadOptions()
{
var options = new StatsMaintenance.CleanupOptions
{
RemoveWithoutPrice = ChkNoPrice.IsChecked == true,
RemoveInconsistentBids = ChkBadBids.IsChecked == true,
RemoveDuplicates = ChkDuplicates.IsChecked == true,
RemoveWithoutWinnerBids = ChkNoWinnerBids.IsChecked == true,
RemoveWithoutWinner = ChkNoWinner.IsChecked == true,
RemoveWithoutValue = ChkNoValue.IsChecked == true
};
// Una soglia illeggibile o fuori scala non deve diventare "togli tutto":
// il filtro resta spento finché il numero non ha senso.
if (ChkCoverage.IsChecked == true &&
double.TryParse(CoverageBox.Text.Trim().Replace(',', '.'),
System.Globalization.NumberStyles.Float,
System.Globalization.CultureInfo.InvariantCulture, out var percento) &&
percento is > 0 and <= 100)
{
options.MinObservedCoverage = percento / 100.0;
}
if (ChkOlderThan.IsChecked == true &&
int.TryParse(DaysBox.Text.Trim(), out var days) && days > 0)
{
options.OlderThan = DateTime.Now.AddDays(-days);
}
return options;
}
private void Option_Changed(object sender, RoutedEventArgs e) => Refresh();
private void Refresh()
{
if (SummaryText == null) return;
var report = StatsMaintenance.Preview(_records, ReadOptions());
SummaryText.Text = report.Removed == 0
? $"Nessuna delle {report.Total} aste verrebbe tolta."
: $"Verrebbero tolte {report.Removed} aste su {report.Total}. " +
$"Ne resterebbero {report.Kept}.";
DetailText.Text = report.ByReason.Count == 0
? ""
: string.Join("\n", report.ByReason
.OrderByDescending(kv => kv.Value)
.Select(kv => $"• {kv.Value} {kv.Key}"));
CleanButton.IsEnabled = report.Removed > 0;
}
private void Clean_Click(object sender, RoutedEventArgs e)
{
var options = ReadOptions();
var report = StatsMaintenance.Preview(_records, options);
if (report.Removed == 0) return;
var answer = MessageBox.Show(this,
$"Tolgo {report.Removed} aste su {report.Total}.\n\n" +
"L'operazione non è reversibile, ma prima viene salvata una copia " +
"dello storico nella cartella dei backup.\n\nProcedo?",
"Pulizia dello storico", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (answer != MessageBoxResult.Yes) return;
try
{
BackupPath = CompletedAuctionsStore.BackupNow();
// La stessa risposta usata per il conto: contare con una regola e
// cancellare con un'altra è il modo classico di far sparire dati che
// nessuno voleva perdere.
var kept = StatsMaintenance.Apply(_records, options);
CompletedAuctionsStore.ReplaceAll(kept);
RemovedCount = report.Removed;
DialogResult = true;
}
catch (Exception ex)
{
MessageBox.Show(this, $"Pulizia non riuscita: {ex.Message}",
"Pulizia dello storico", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}