using GerbilManagerWebAPI.Import.Rpro3;
using GerbilManagerWebAPI.Models;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace GerbilManager.Tests
{
    /// <summary>
    /// Tests für den RennmausPro-III-Importer (Reader + Dedup + Execute).
    /// Die meisten Tests bauen eine hermetische Mini-SQLite im RPRO3-Schema; ein optionaler
    /// Test gegen die echte entpackte DB läuft nur, wenn sie lokal vorhanden ist.
    /// </summary>
    public class Rpro3ImportTests
    {
        static Rpro3ImportTests()
        {
            // CP1252 für die Tests verfügbar machen (die Produktion registriert es im Reader-Ctor).
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
        }

        // ── Unit: Decode / JDN / Genotyp ──────────────────────────────

        [Fact]
        public void JdnToDate_converts_known_julian_day_numbers()
        {
            // Blacky _BIRTH = 2455036.0 → 2009-07-23 (siehe rpro3-vergleich.md).
            Assert.Equal(new DateOnly(2009, 7, 23), Rpro3Reader.JdnToDate(2455036.0));
            Assert.Null(Rpro3Reader.JdnToDate(0));
            Assert.Null(Rpro3Reader.JdnToDate(null));
        }

        [Fact]
        public void SmartDecode_prefers_utf8_then_cp1252()
        {
            var utf8 = System.Text.Encoding.UTF8.GetBytes("männlich");
            Assert.Equal("männlich", Rpro3Reader.SmartDecode(utf8));

            var cp1252 = System.Text.Encoding.GetEncoding(1252).GetBytes("männlich");
            // CP1252-Bytes sind kein gültiges UTF-8 → Fallback dekodiert korrekt.
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
            Assert.Equal("männlich", Rpro3Reader.SmartDecode(cp1252));
        }

        [Fact]
        public void CleanGenotype_strips_brackets_keeps_dash()
        {
            Assert.Equal("aa Ccchm DD EE GG Pp spsp", Rpro3Reader_CleanGenotype("aa Cc[chm] DD EE GG Pp spsp"));
            Assert.Equal("Kim AA C- Dd", Rpro3Reader_CleanGenotype("Kim AA C- Dd"));
        }

        private static string? Rpro3Reader_CleanGenotype(string s)
        {
            // CleanGenotype ist internal in Rpro3ImportService → über InternalsVisibleTo erreichbar.
            var m = typeof(Rpro3ImportService).GetMethod("CleanGenotype",
                System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
            return (string?)m!.Invoke(null, new object?[] { s });
        }

        // ── Unit: Dedup ───────────────────────────────────────────────

        [Fact]
        public void Dedup_merges_compatible_same_name_records()
        {
            var animals = new List<Rpro3Animal>
            {
                Ext("u1", "Alice", new DateOnly(2010, 7, 19), "Schimmel", "Clan A"),
                Ext("u2", "Alice", new DateOnly(2010, 7, 19), "Schimmel", ""),      // kompatibel → merge
                Ext("u3", "Alice", null, "Schimmel", "Clan A"),                     // kompatibel → merge
                Ext("u4", "Alice", new DateOnly(2001, 1, 1), "Schwarz", "Clan B"),  // Konflikt → eigener Cluster
            };
            var r = Rpro3Dedup.Run(animals);
            // Mind. ein Merge-Cluster (u1/u2/u3), u4 separat → Name "Alice" mehrdeutig.
            Assert.Single(r.MergeClusters);
            Assert.Equal(3, r.MergeClusters.Values.First().Count);
            Assert.Contains(r.Ambiguous, a => a.Name == "Alice");
        }

        [Fact]
        public void Dedup_does_not_merge_placeholder_names()
        {
            var animals = new List<Rpro3Animal>
            {
                Ext("u1", "unbekannt", null, "", ""),
                Ext("u2", "unbekannt", null, "", ""),
            };
            var r = Rpro3Dedup.Run(animals);
            Assert.Empty(r.MergeClusters);
            Assert.Equal(2, r.Placeholders.Count);
        }

        [Fact]
        public void Dedup_force_merges_variants_declared_same_by_breeder()
        {
            // Zwei Varianten, die der Auto-Dedup wegen Farbkonflikt getrennt lässt …
            var animals = new List<Rpro3Animal>
            {
                Ext("u1", "Akiro", new DateOnly(2008, 2, 5), "Polarfuchs", "Privatzucht"),       // Variante B
                Ext("u2", "Akiro", new DateOnly(2008, 2, 6), "Polarfuchs, hell", "unbekannt"),   // Variante C
            };
            // ohne Entscheidung: getrennt (Farbe + DOB unterschiedlich → Konflikt)
            Assert.Empty(Rpro3Dedup.Run(animals).MergeClusters);

            // … werden per „Same"-Entscheidung der Züchterin zusammengelegt.
            var decisions = new Rpro3Decisions
            {
                Decisions = { new Rpro3Decision { Name = "Akiro", Same = { new() { "u1", "u2" } } } }
            };
            var r = Rpro3Dedup.Run(animals, decisions);
            Assert.Single(r.MergeClusters);
            Assert.Equal(2, r.MergeClusters.Values.First().Count);
            Assert.Equal(r.RidToRoot["u1"], r.RidToRoot["u2"]);
        }

        [Fact]
        public void Dedup_force_splits_variants_declared_different_by_breeder()
        {
            // Zwei Datensätze, die der Auto-Dedup zusammenlegen würde (kompatibel) …
            var animals = new List<Rpro3Animal>
            {
                Ext("u1", "Max", new DateOnly(2013, 2, 1), "Marder", "Clan A"),
                Ext("u2", "Max", new DateOnly(2013, 2, 1), "Marder", "Clan A"),
            };
            Assert.Single(Rpro3Dedup.Run(animals).MergeClusters);

            // … bleiben durch „Different" getrennt.
            var decisions = new Rpro3Decisions
            {
                Decisions = { new Rpro3Decision { Name = "Max", Different = { new() { "u1" }, new() { "u2" } } } }
            };
            var r = Rpro3Dedup.Run(animals, decisions);
            Assert.Empty(r.MergeClusters);
            Assert.NotEqual(r.RidToRoot["u1"], r.RidToRoot["u2"]);
        }

        [Fact]
        public void Rpro3Decisions_load_returns_empty_when_file_missing()
        {
            var d = Rpro3Decisions.Load(Path.Combine(Path.GetTempPath(), "does-not-exist-" + Guid.NewGuid().ToString("N") + ".json"));
            Assert.Empty(d.Decisions);
        }

        [Fact]
        public void Rpro3Decisions_roundtrips_through_json()
        {
            var path = Path.Combine(Path.GetTempPath(), "rpro3-dec-" + Guid.NewGuid().ToString("N") + ".json");
            File.WriteAllText(path,
                "{\"decisions\":[{\"name\":\"Bura\",\"same\":[[\"228\",\"u2128\"]],\"fields\":{\"228\":{\"origin\":\"Sarah Wörz\"}}}," +
                "{\"name\":\"MilkyWay\",\"same\":[[\"u1031\",\"u1019\"]],\"fields\":{\"u1031\":{\"genotype\":\"aa Cc[h] DD ee Gg P- spsp\",\"color\":\"Kohlfuchs-Hell\"}}}]}");
            try
            {
                var d = Rpro3Decisions.Load(path);
                Assert.Equal(2, d.Decisions.Count);
                Assert.Equal("Sarah Wörz", d.BuildFieldIndex()["228"].Origin);
                Assert.Equal(new[] { "228", "u2128" }, d.SameGroups().First());
                // Gencode-Override (z. B. MilkyWay: korrektes C-Locus c[h]) muss durch den JSON-Roundtrip kommen.
                Assert.Equal("aa Cc[h] DD ee Gg P- spsp", d.BuildFieldIndex()["u1031"].Genotype);
            }
            finally { File.Delete(path); }
        }

        // ── Integration: Reader + Execute gegen eine Mini-RPRO3-DB ────

        [Fact]
        public async Task Execute_imports_animals_litters_contacts_and_is_idempotent()
        {
            var dbPath = BuildMiniRpro3();
            try
            {
                var data = new Rpro3Reader().ReadFromDbFile(dbPath);
                Assert.Equal(2, data.Animals.Count(a => a.Src == Rpro3Src.Stamm));
                Assert.True(data.Animals.Count(a => a.Src == Rpro3Src.Fremd) >= 2);

                using var efConn = new SqliteConnection("DataSource=:memory:");
                efConn.Open();
                var opts = new DbContextOptionsBuilder<ApplicationContext>().UseSqlite(efConn).Options;
                using var ctx = new ApplicationContext(opts);
                ctx.Database.EnsureCreated();

                var config = new ConfigurationBuilder().Build();
                var service = new Rpro3ImportService(ctx, config, null);

                var analyze = await service.AnalyzeAsync(data, photosProvided: false, availablePhotoFiles: null);
                Assert.Equal(2, analyze.Counts.OwnAnimals);
                Assert.True(analyze.NewVsCurrentNew >= 2);

                var first = await service.ExecuteAsync(data, Path.GetTempPath(), photosProvided: false, photoSourcePaths: null);
                Assert.True(first.GerbilsImported >= 4);   // 2 stamm + ≥2 fremd
                Assert.Equal(1, first.LittersImported >= 1 ? 1 : 0); // mind. 1 Wurf importiert
                var gerbilCount1 = await ctx.Gerbils.CountAsync();
                var litterCount1 = await ctx.Litters.CountAsync();

                // Re-Run: idempotent — gleiche Zeilenzahl, keine Dubletten.
                var second = await service.ExecuteAsync(data, Path.GetTempPath(), photosProvided: false, photoSourcePaths: null);
                Assert.Equal(gerbilCount1, await ctx.Gerbils.CountAsync());
                Assert.Equal(litterCount1, await ctx.Litters.CountAsync());

                // Pedigree: Wurf hat Mutter + Vater verknüpft (resolved gegen importierte Tiere).
                var litter = await ctx.Litters.FirstAsync(l => l.Name!.StartsWith("Wurf"));
                Assert.NotNull(litter.MotherId);
                Assert.NotNull(litter.FatherId);

                // Genotyp wurde aus _FCODE übernommen + Klammern entfernt.
                var blacky = await ctx.Gerbils.FirstAsync(g => g.Name == "Blacky");
                Assert.Equal("aa Ccchm DD EE GG Pp spsp", blacky.Genotype);
                Assert.True(blacky.IsResident);

                // Encoding: "männlich" korrekt dekodiert (Latin-1-Quelle).
                Assert.Equal(Gender.male, blacky.Gender);
            }
            finally { try { File.Delete(dbPath); } catch { } }
        }

        // ── Integration: Feature-Tabellen (Becken/Erwerb/Reservierung/Rücknahme/Warteliste/Ausstellung) ──

        [Fact]
        public async Task Execute_imports_feature_tables_and_is_idempotent()
        {
            var dbPath = BuildMiniRpro3();
            try
            {
                var data = new Rpro3Reader().ReadFromDbFile(dbPath);
                // Reader hat alle Feature-Tabellen erfasst.
                Assert.Equal(2, data.Becken.Count);
                Assert.Single(data.Acquisitions);
                Assert.Single(data.Abgeben);
                Assert.Single(data.Abstat);
                Assert.Single(data.Getback);
                Assert.Single(data.Nachfrage);
                Assert.Single(data.Ausstellungen);
                Assert.Equal(1, data.StammBecken["1"]); // Blacky → Becken 1

                using var efConn = new SqliteConnection("DataSource=:memory:");
                efConn.Open();
                var opts = new DbContextOptionsBuilder<ApplicationContext>().UseSqlite(efConn).Options;
                using var ctx = new ApplicationContext(opts);
                ctx.Database.EnsureCreated();
                var service = new Rpro3ImportService(ctx, new ConfigurationBuilder().Build(), null);

                var res = await service.ExecuteAsync(data, Path.GetTempPath(), photosProvided: false, photoSourcePaths: null);
                Assert.Equal(2, res.EnclosuresImported);
                Assert.Equal(1, res.AcquisitionsImported);
                Assert.Equal(2, res.ReservationsImported);   // abgeben(Blacky, reserviert) + abstat(Kuke, abgegeben)
                Assert.Equal(1, res.ReturnsImported);
                Assert.Equal(1, res.WaitingListImported);
                Assert.Equal(1, res.ExhibitionsImported);

                // Becken → Gehege; Blacky ist Becken 1 zugeordnet.
                Assert.Equal(2, await ctx.Enclosures.CountAsync());
                var kaefig = await ctx.Enclosures.FirstAsync(e => e.Name == "Käfig A");
                Assert.Equal("80x35x40", kaefig.Size);
                Assert.Equal(3, kaefig.Capacity);
                Assert.Equal(60, kaefig.CleaningCycleDays);
                var blacky = await ctx.Gerbils.FirstAsync(g => g.Name == "Blacky");
                Assert.Equal(kaefig.Id, blacky.EnclosureId);

                // Erwerb verknüpft auf Blacky mit Preis/Datum.
                var acq = await ctx.AcquisitionRecords.SingleAsync();
                Assert.Equal(blacky.Id, acq.GerbilId);
                Assert.Equal(9.5m, acq.Price);
                Assert.NotNull(acq.Date);

                // Reservierung: Blacky reserviert für Lisa M.
                var resv = await ctx.SaleReservations.FirstAsync(r => r.GerbilId == blacky.Id);
                Assert.Equal("reserviert", resv.Status);
                Assert.Equal("Lisa M.", resv.ContactName);

                // Abgabe-Abschluss: Kuke → abgegeben.
                var kuke = await ctx.Gerbils.FirstAsync(g => g.Name == "Kuke");
                var kukeRes = await ctx.SaleReservations.FirstAsync(r => r.GerbilId == kuke.Id);
                Assert.Equal("abgegeben", kukeRes.Status);
                Assert.Equal(15.0m, kukeRes.Price);

                // Rücknahme: Blacky kam zurück.
                var ret = await ctx.ReturnRecords.SingleAsync();
                Assert.Equal(blacky.Id, ret.GerbilId);
                Assert.Equal(15.0m, ret.OriginalPrice);
                Assert.Equal("Lisa M.", ret.FromContactName);

                // Warteliste: männlicher Schimmel.
                var wl = await ctx.WaitingListEntries.SingleAsync();
                Assert.Equal("male", wl.WishGender);
                Assert.Equal("Schimmel", wl.WishColor);
                Assert.Equal("offen", wl.Status);

                // Ausstellung: Blacky, 1. Platz, BOB.
                var exh = await ctx.ExhibitionResults.SingleAsync();
                Assert.Equal(blacky.Id, exh.GerbilId);
                Assert.Equal("Schau 2011", exh.EventName);
                Assert.Equal("1. Platz", exh.Placement);
                Assert.Equal("BOB", exh.Award);

                // Re-Run: idempotent — keine Dubletten in den Feature-Tabellen.
                await service.ExecuteAsync(data, Path.GetTempPath(), photosProvided: false, photoSourcePaths: null);
                Assert.Equal(2, await ctx.Enclosures.CountAsync());
                Assert.Equal(1, await ctx.AcquisitionRecords.CountAsync());
                Assert.Equal(2, await ctx.SaleReservations.CountAsync()); // Blacky + Kuke
                Assert.Equal(1, await ctx.ReturnRecords.CountAsync());
                Assert.Equal(1, await ctx.WaitingListEntries.CountAsync());
                Assert.Equal(1, await ctx.ExhibitionResults.CountAsync());
            }
            finally { try { File.Delete(dbPath); } catch { } }
        }

        // ── Helpers ──

        private static Rpro3Animal Ext(string rid, string name, DateOnly? dob, string farbe, string origin) =>
            new() { Rid = rid, Src = Rpro3Src.Fremd, Name = name, Dob = dob, Farbe = farbe, Origin = origin };

        /// <summary>Baut eine minimale SQLite im RPRO3-Schema (Latin-1-Geschlecht, JDN-Daten).</summary>
        private static string BuildMiniRpro3()
        {
            var path = Path.Combine(Path.GetTempPath(), "mini-rpro3-" + Guid.NewGuid().ToString("N") + ".db");
            using var conn = new SqliteConnection($"DataSource={path}");
            conn.Open();
            void Exec(string sql) { using var c = conn.CreateCommand(); c.CommandText = sql; c.ExecuteNonQuery(); }

            Exec("CREATE TABLE herk_tb (id INTEGER, _BEZ, _ANREDE, _VNAME, _NNAME, _CLAN, _STR, _ORT, _PLZ, _TELP, _TELD, _MAIL, _HTTP, _MEMO, _BEM)");
            Exec("CREATE TABLE abn_tb (id INTEGER, _BEZ, _ANREDE, _VNAME, _NNAME, _CLAN, _STR, _ORT, _PLZ, _TELP, _TELD, _MAIL, _HTTP, _MEMO, _BEM)");
            Exec("CREATE TABLE baum_tb (id, _MID, _PID)");
            Exec("CREATE TABLE stamm_tb (id INTEGER, _NAME, _SEX, _BIRTH, _HERKUNFT, _ZB, _STATUS, _FEHLER, _KASTRAT_DATE, _BECKEN)");
            Exec("CREATE TABLE fremd_tb (id INTEGER, _NAME, _SEX, _BIRTH, _ZB, _HERK, _MID, _PID, _TODAM, _KASTRAT_DATE)");
            Exec("CREATE TABLE wurf_tb (id INTEGER, _MID, _PID, _AM, _BEZ, _BEM)");
            Exec("CREATE TABLE wurftier_tb (id, _WID, _NAME, _SEX, _BIRTH, _SID, _TODAM, _WARUM, _ABAM, _ABN, _PRICE, _ZB, _FEHLER)");
            Exec("CREATE TABLE color_tb (id, _FARBE, _FCODE)");
            Exec("CREATE TABLE wurfcolor_tb (id, _FARBE, _FCODE)");
            Exec("CREATE TABLE fremdcolor_tb (id, _FARBE, _FCODE)");
            Exec("CREATE TABLE tod_tb (tid, _AM, _WARUM)");
            Exec("CREATE TABLE waage_tb (_TID, _GRAMM, _DATE, _BEM)");
            Exec("CREATE TABLE jungwaage_tb (_TID, _WID, _GRAMM, _DATE, _BEM)");
            Exec("CREATE TABLE krank_tb (_TID, _DATE, _BEM, _MED)");
            Exec("CREATE TABLE diary_tb (_TID, _BEZ, _DATE, _DESC)");
            Exec("CREATE TABLE photo_tb (id, _P1, _P2, _P3)");
            // Feature-Tabellen.
            Exec("CREATE TABLE becken_tb (id INTEGER, _BEZ, _SIZE, _MENGE, _CLEANED, _CYCLUS, _NEXT)");
            Exec("CREATE TABLE herktier_tb (id INTEGER, _TID, _DATE, _PRICE, _BEM, _ART)");
            Exec("CREATE TABLE abgeben_tb (tid, _RES, _BEM, _TERMIN, _ABN, _BEZ)");
            Exec("CREATE TABLE abstat_tb (tid, _IDABN, _AM, _PRICE, _ART, _BEM)");
            Exec("CREATE TABLE getback_tb (id INTEGER, _TID, _ZAM, _ZPREIS, _AM, _PREIS, _ABN, _BEM)");
            Exec("CREATE TABLE nachfrage_tb (id INTEGER, _COLOR, _SEX, _DATE, _ABN, _CODE, _VOM, _STATUS, _ART)");
            Exec("CREATE TABLE ausz_tb (id INTEGER, _TID, _VERANSTALTUNG, _DATE, _ORT, _PLATZ, _AUSZ, _EXTRA, _JUROR, _BEM)");

            // Kontakte
            Exec("INSERT INTO herk_tb (id,_BEZ,_CLAN,_ORT,_MAIL) VALUES (1,'eigene Zucht','','','')");
            Exec("INSERT INTO herk_tb (id,_BEZ,_CLAN,_ORT,_MAIL) VALUES (61,'M.Knoss GG','Clan X','Gießen','a@b.de')");

            // Geschlecht als Latin-1-Bytes einfügen (BLOB), um den smart_decode-Fallback zu testen.
            var maennBytes = System.Text.Encoding.GetEncoding(1252).GetBytes("männlich");
            var weibBytes = System.Text.Encoding.UTF8.GetBytes("weiblich");
            void InsertStamm(int id, string name, byte[] sex, double birth, int herk, string zb, int becken = 0)
            {
                using var c = conn.CreateCommand();
                c.CommandText = "INSERT INTO stamm_tb (id,_NAME,_SEX,_BIRTH,_HERKUNFT,_ZB,_STATUS,_FEHLER,_BECKEN) VALUES ($id,$n,$s,$b,$h,$z,3,'',$bk)";
                c.Parameters.AddWithValue("$id", id);
                c.Parameters.AddWithValue("$n", name);
                c.Parameters.AddWithValue("$s", sex);
                c.Parameters.AddWithValue("$b", birth);
                c.Parameters.AddWithValue("$h", herk);
                c.Parameters.AddWithValue("$z", zb);
                c.Parameters.AddWithValue("$bk", becken);
                c.ExecuteNonQuery();
            }
            InsertStamm(1, "Blacky", maennBytes, 2455036.0, 61, "ZdKC-B.09.2009", becken: 1);
            InsertStamm(2, "Kuke", weibBytes, 2455093.0, 61, "ZdKC-B.10.2009");

            // Genotyp (Bracket-Notation) für Blacky.
            Exec("INSERT INTO color_tb (id,_FARBE,_FCODE) VALUES ('1','Schwarz','aa Cc[chm] DD EE GG Pp spsp')");

            // Externe Ahnen (Eltern von Blacky & Kuke via baum_tb).
            Exec("INSERT INTO fremd_tb (id,_NAME,_SEX,_BIRTH,_HERK,_MID,_PID) VALUES (1,'Oma','weiblich',0,1,'','')");
            Exec("INSERT INTO fremd_tb (id,_NAME,_SEX,_BIRTH,_HERK,_MID,_PID) VALUES (2,'Opa','männlich',0,1,'','')");
            Exec("INSERT INTO baum_tb (id,_MID,_PID) VALUES ('1','u1','u2')");      // Blacky Eltern = Oma×Opa
            Exec("INSERT INTO baum_tb (id,_MID,_PID) VALUES ('2','u1','u2')");      // Kuke Eltern = Oma×Opa

            // Wurf: Mutter Kuke (2) × Vater Blacky (1)
            Exec("INSERT INTO wurf_tb (id,_MID,_PID,_AM,_BEZ,_BEM) VALUES (1,'2','1',2455246.0,'Wurf A','Erster Wurf')");
            Exec("INSERT INTO wurftier_tb (id,_WID,_NAME,_SEX,_BIRTH,_SID,_TODAM,_ABAM,_ABN,_PRICE,_ZB) VALUES ('1j1','1','Alvin','männlich',2455246.0,'','','',NULL,'','21 A')");

            // Gewicht + Krankheit für Blacky.
            Exec("INSERT INTO waage_tb (_TID,_GRAMM,_DATE,_BEM) VALUES ('1',55.0,2455083.0,'')");
            Exec("INSERT INTO krank_tb (_TID,_DATE,_BEM,_MED) VALUES ('1',2455077.0,'Prellung','')");

            // Feature-Tabellen-Daten.
            // Abnehmer-Kontakt (für Reservierung/Rücknahme/Warteliste).
            Exec("INSERT INTO abn_tb (id,_BEZ,_VNAME,_NNAME) VALUES (5,'Lisa M.','Lisa','Müller')");
            // Becken 1 (Blacky wohnt dort, _BECKEN=1), Becken 2 ohne Bewohner.
            Exec("INSERT INTO becken_tb (id,_BEZ,_SIZE,_MENGE,_CLEANED,_CYCLUS,_NEXT) VALUES (1,'Käfig A','80x35x40',3,2455595.0,60,2455655.0)");
            Exec("INSERT INTO becken_tb (id,_BEZ,_SIZE,_MENGE,_CLEANED,_CYCLUS,_NEXT) VALUES (2,'Terrarium','55x48x110',32,2455638.0,90,2455728.0)");
            // Erwerb: Blacky (stamm 1) am JDN für 9.50.
            Exec("INSERT INTO herktier_tb (id,_TID,_DATE,_PRICE,_BEM) VALUES (61,'1',2455076.0,9.5,'gekauft')");
            // Reservierung: Blacky (stamm 1) reserviert für abn 5.
            Exec("INSERT INTO abgeben_tb (tid,_RES,_BEM,_TERMIN,_ABN,_BEZ) VALUES ('1',1,'',2455730.0,5,0)");
            // Abgabe-Abschluss: Kuke (stamm 2) abgegeben an abn 5 für 15.
            Exec("INSERT INTO abstat_tb (tid,_IDABN,_AM,_PRICE,_BEM) VALUES ('2',5,2455716.0,15.0,'Zog aus.')");
            // Rücknahme: Blacky kam zurück von abn 5.
            Exec("INSERT INTO getback_tb (id,_TID,_ZAM,_ZPREIS,_AM,_PREIS,_ABN,_BEM) VALUES (2,'1',2455992.0,0.0,2455798.0,15.0,5,'kam zurück')");
            // Warteliste: Wunsch nach männlichem Schimmel von abn 5.
            Exec("INSERT INTO nachfrage_tb (id,_COLOR,_SEX,_DATE,_ABN,_CODE,_VOM,_STATUS) VALUES (1,'Schimmel','männlich',0.0,5,'egal',2456172.0,'')");
            // Ausstellung: ein Ergebnis für Blacky (in echten Backups oft leer).
            Exec("INSERT INTO ausz_tb (id,_TID,_VERANSTALTUNG,_DATE,_ORT,_PLATZ,_AUSZ,_JUROR,_BEM) VALUES (1,'1','Schau 2011',2455700.0,'Halle A','1. Platz','BOB','Frau X','schön')");

            conn.Close();
            SqliteConnection.ClearAllPools();
            return path;
        }
    }
}
