<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;

/**
 * Raeumt die Doppelungen aus dem Versandregister.
 *
 * RecordSentMail war doppelt angemeldet — von Hand im AppServiceProvider und
 * durch Laravels Erkennung der Zuhoerer in app/Listeners. Jeder Versand
 * hinterliess dadurch ZWEI gleiche Zeilen. Die Anmeldung von Hand ist weg;
 * was seither geschrieben wird, stimmt. Der Altbestand nicht: dort steht zu
 * jedem Vorgang eine Zustellung, die es nie gab, und das Register beantwortet
 * genau die eine Frage falsch, fuer die es gebaut wurde — hat der Kunde das
 * bekommen, und wie oft.
 *
 * Die Regel ist die des Fehlers, rueckwaerts gelesen: der Zuhoerer verdoppelte
 * jeden Versand exakt, also bleibt von jeder Gruppe gleicher Zeilen die
 * HAELFTE stehen, die aeltere. Eine Gruppe aus vier Zeilen waren zwei echte
 * Versande — daraus werden zwei, nicht eine. Ungerade Gruppen kann dieser
 * Fehler nicht erzeugt haben; sollte doch eine auftauchen, wird aufgerundet,
 * damit im Zweifel eine Zeile zu viel stehen bleibt statt eine zu wenig.
 *
 * Gleich heisst: derselbe Empfaenger, derselbe Betreff, dieselbe Mailklasse,
 * derselbe Zeitpunkt. Zwei echte Mails, die in derselben Sekunde mit
 * identischem Betreff an dieselbe Adresse gingen, waren ebenfalls verdoppelt —
 * sie kommen als vier an und gehen als zwei heraus.
 */
return new class extends Migration
{
    public function up(): void
    {
        $gruppen = DB::table('sent_mails')
            ->select('to', 'subject', 'mailable', 'sent_at')
            ->selectRaw('COUNT(*) as anzahl')
            ->groupBy('to', 'subject', 'mailable', 'sent_at')
            ->having('anzahl', '>', 1)
            ->get();

        foreach ($gruppen as $gruppe) {
            $ids = DB::table('sent_mails')
                ->where('to', $gruppe->to)
                ->where('subject', $gruppe->subject)
                // Beide Spalten duerfen leer sein, und `= NULL` trifft nichts.
                ->when($gruppe->mailable === null,
                    fn ($q) => $q->whereNull('mailable'),
                    fn ($q) => $q->where('mailable', $gruppe->mailable))
                ->when($gruppe->sent_at === null,
                    fn ($q) => $q->whereNull('sent_at'),
                    fn ($q) => $q->where('sent_at', $gruppe->sent_at))
                ->orderBy('id')
                ->pluck('id');

            $behalten = (int) ceil($ids->count() / 2);
            $weg = $ids->slice($behalten)->all();

            if ($weg !== []) {
                DB::table('sent_mails')->whereIn('id', $weg)->delete();
            }
        }
    }

    public function down(): void
    {
        // Geloeschte Zeilen kommen nicht zurueck, und eine Zeile zu erfinden
        // waere schlimmer als die Luecke: das Register darf nichts behaupten.
    }
};
