using MongoDB.Bson;
using MongoDB.Driver;
using MongoMigrations.Core;

namespace adas_core.Infrastructure.Migrations.MongoMigrations;

// ReSharper disable once InconsistentNaming
/// <summary>
/// Represents a database migration (version 0.1.0) responsible for updating the patient data schema.
/// </summary>
/// <remarks>
/// Inherits from the <see cref="Migration"/> base class, indicating it is intended to be applied as part of an Entity Framework (or similar) migration pipeline to evolve the underlying data store.
/// </remarks>
public class U_0_1_0_UpdateDataPatien : Migration
{
    public U_0_1_0_UpdateDataPatien() : base(10)
    {
        Description =
            "Transforma person.historicalIds y historicalLocations en arrays con fechas y realiza merge sobre patients.";
    }

    public override void Update()
    {
        var collectionPatient = Database.GetCollection<BsonDocument>("patients");

        var pipelinePatient = new[]
        {
            new BsonDocument("$addFields", new BsonDocument
            {
                {
                    "person.historicalIds", new BsonDocument("$cond", new BsonDocument
                    {
                        // si ya es array → no tocar
                        { "if", new BsonDocument("$isArray", "$person.historicalIds") },
                        { "then", "$person.historicalIds" },
                        // si es document → migrar
                        {
                            "else", new BsonDocument("$map", new BsonDocument
                            {
                                { "input", new BsonDocument("$objectToArray", "$person.historicalIds") },
                                { "as", "id" },
                                {
                                    "in", new BsonDocument
                                    {
                                        {
                                            "time",
                                            new BsonDocument("$dateFromString",
                                                new BsonDocument("dateString", "$$id.k"))
                                        },
                                        { "patientIds", "$$id.v" }
                                    }
                                }
                            })
                        }
                    })
                },
                {
                    "historicalLocations", new BsonDocument("$cond", new BsonDocument
                    {
                        { "if", new BsonDocument("$isArray", "$historicalLocations") },
                        { "then", "$historicalLocations" },
                        {
                            "else", new BsonDocument("$map", new BsonDocument
                            {
                                { "input", new BsonDocument("$objectToArray", "$historicalLocations") },
                                { "as", "location" },
                                {
                                    "in", new BsonDocument
                                    {
                                        {
                                            "admTime",
                                            new BsonDocument("$dateFromString",
                                                new BsonDocument("dateString", "$$location.k"))
                                        },
                                        { "patientLocation", "$$location.v" }
                                    }
                                }
                            })
                        }
                    })
                }
            }),
            new BsonDocument("$merge", new BsonDocument
            {
                { "into", "patients" },
                { "whenMatched", "replace" }, // aquí SÍ es seguro (no hay _t)
                { "whenNotMatched", "discard" }
            })
        };

        collectionPatient.Aggregate<BsonDocument>(pipelinePatient).ToList();
        
        var collectionAdmission = Database.GetCollection<BsonDocument>("admissions");

        var pipelineAdmission = new[]
        {
            new BsonDocument("$addFields", new BsonDocument
            {
                {
                    "person.historicalIds", new BsonDocument("$cond", new BsonDocument
                    {
                        // si ya es array → no tocar
                        { "if", new BsonDocument("$isArray", "$person.historicalIds") },
                        { "then", "$person.historicalIds" },
                        // si es document → migrar
                        {
                            "else", new BsonDocument("$map", new BsonDocument
                            {
                                { "input", new BsonDocument("$objectToArray", "$person.historicalIds") },
                                { "as", "id" },
                                {
                                    "in", new BsonDocument
                                    {
                                        {
                                            "time",
                                            new BsonDocument("$dateFromString",
                                                new BsonDocument("dateString", "$$id.k"))
                                        },
                                        { "patientIds", "$$id.v" }
                                    }
                                }
                            })
                        }
                    })
                },
                {
                    "historicalLocations", new BsonDocument("$cond", new BsonDocument
                    {
                        { "if", new BsonDocument("$isArray", "$historicalLocations") },
                        { "then", "$historicalLocations" },
                        {
                            "else", new BsonDocument("$map", new BsonDocument
                            {
                                { "input", new BsonDocument("$objectToArray", "$historicalLocations") },
                                { "as", "location" },
                                {
                                    "in", new BsonDocument
                                    {
                                        {
                                            "admTime",
                                            new BsonDocument("$dateFromString",
                                                new BsonDocument("dateString", "$$location.k"))
                                        },
                                        { "patientLocation", "$$location.v" }
                                    }
                                }
                            })
                        }
                    })
                }
            }),
            new BsonDocument("$merge", new BsonDocument
            {
                { "into", "admissions" },
                { "whenMatched", "replace" }, // aquí SÍ es seguro (no hay _t)
                { "whenNotMatched", "discard" }
            })
        };

        collectionAdmission.Aggregate<BsonDocument>(pipelineAdmission).ToList();
        
        var collectionArchivePatient = Database.GetCollection<BsonDocument>("archive_patient");

        var pipelineArchivePatient = new[]
        {
            new BsonDocument("$addFields", new BsonDocument
            {
                {
                    "person.historicalIds", new BsonDocument("$cond", new BsonDocument
                    {
                        // si ya es array → no tocar
                        { "if", new BsonDocument("$isArray", "$person.historicalIds") },
                        { "then", "$person.historicalIds" },
                        // si es document → migrar
                        {
                            "else", new BsonDocument("$map", new BsonDocument
                            {
                                { "input", new BsonDocument("$objectToArray", "$person.historicalIds") },
                                { "as", "id" },
                                {
                                    "in", new BsonDocument
                                    {
                                        {
                                            "time",
                                            new BsonDocument("$dateFromString",
                                                new BsonDocument("dateString", "$$id.k"))
                                        },
                                        { "patientIds", "$$id.v" }
                                    }
                                }
                            })
                        }
                    })
                },
                {
                    "historicalLocations", new BsonDocument("$cond", new BsonDocument
                    {
                        { "if", new BsonDocument("$isArray", "$historicalLocations") },
                        { "then", "$historicalLocations" },
                        {
                            "else", new BsonDocument("$map", new BsonDocument
                            {
                                { "input", new BsonDocument("$objectToArray", "$historicalLocations") },
                                { "as", "location" },
                                {
                                    "in", new BsonDocument
                                    {
                                        {
                                            "admTime",
                                            new BsonDocument("$dateFromString",
                                                new BsonDocument("dateString", "$$location.k"))
                                        },
                                        { "patientLocation", "$$location.v" }
                                    }
                                }
                            })
                        }
                    })
                }
            }),
            new BsonDocument("$merge", new BsonDocument
            {
                { "into", "archive_patient" },
                { "whenMatched", "replace" }, // aquí SÍ es seguro (no hay _t)
                { "whenNotMatched", "discard" }
            })
        };

        collectionArchivePatient.Aggregate<BsonDocument>(pipelineArchivePatient).ToList();
    }

    // NO usado por MongoMigrations.Core
    // Solo para ejecución manual si hiciera falta
    public void Down()
    {
        var collectionPatient = Database.GetCollection<BsonDocument>("patients");

        var pipelinePatient = new[]
        {
            new BsonDocument("$addFields", new BsonDocument
            {
                {
                    "person.historicalIds", new BsonDocument("$cond", new BsonDocument
                    {
                        // si ya es document → no tocar
                        { "if", new BsonDocument("$not", new BsonArray { new BsonDocument("$isArray", "$person.historicalIds") }) },
                        { "then", "$person.historicalIds" },
                        // si es array → revertir
                        {
                            "else", new BsonDocument("$arrayToObject", new BsonArray
                            {
                                new BsonDocument
                                {
                                    {
                                        "$map", new BsonDocument
                                        {
                                            { "input", "$person.historicalIds" },
                                            { "as", "id" },
                                            {
                                                "in", new BsonDocument
                                                {
                                                    {
                                                        "k", new BsonDocument("$dateToString", new BsonDocument
                                                        {
                                                            { "format", "%Y-%m-%dT%H:%M:%S.%LZ" },
                                                            { "date", "$$id.time" }
                                                        })
                                                    },
                                                    { "v", "$$id.patientIds" }
                                                }
                                            }
                                        }
                                    }
                                }
                            })
                        }
                    })
                },
                {
                    "historicalLocations", new BsonDocument("$cond", new BsonDocument
                    {
                        { "if", new BsonDocument("$not", new BsonArray { new BsonDocument("$isArray", "$historicalLocations") }) },
                        { "then", "$historicalLocations" },
                        {
                            "else", new BsonDocument("$arrayToObject", new BsonArray
                            {
                                new BsonDocument
                                {
                                    {
                                        "$map", new BsonDocument
                                        {
                                            { "input", "$historicalLocations" },
                                            { "as", "location" },
                                            {
                                                "in", new BsonDocument
                                                {
                                                    {
                                                        "k", new BsonDocument("$dateToString", new BsonDocument
                                                        {
                                                            { "format", "%Y-%m-%dT%H:%M:%S.%LZ" },
                                                            { "date", "$$location.admTime" }
                                                        })
                                                    },
                                                    { "v", "$$location.patientLocation" }
                                                }
                                            }
                                        }
                                    }
                                }
                            })
                        }
                    })
                }
            }),
            new BsonDocument("$merge", new BsonDocument
            {
                { "into", "patients" },
                { "whenMatched", "replace" },
                { "whenNotMatched", "discard" }
            })
        };

        collectionPatient.Aggregate<BsonDocument>(pipelinePatient).ToList();
        
         var collectionAdm = Database.GetCollection<BsonDocument>("admissions");

        var pipelineAdm = new[]
        {
            new BsonDocument("$addFields", new BsonDocument
            {
                {
                    "person.historicalIds", new BsonDocument("$cond", new BsonDocument
                    {
                        // si ya es document → no tocar
                        { "if", new BsonDocument("$not", new BsonArray { new BsonDocument("$isArray", "$person.historicalIds") }) },
                        { "then", "$person.historicalIds" },
                        // si es array → revertir
                        {
                            "else", new BsonDocument("$arrayToObject", new BsonArray
                            {
                                new BsonDocument
                                {
                                    {
                                        "$map", new BsonDocument
                                        {
                                            { "input", "$person.historicalIds" },
                                            { "as", "id" },
                                            {
                                                "in", new BsonDocument
                                                {
                                                    {
                                                        "k", new BsonDocument("$dateToString", new BsonDocument
                                                        {
                                                            { "format", "%Y-%m-%dT%H:%M:%S.%LZ" },
                                                            { "date", "$$id.time" }
                                                        })
                                                    },
                                                    { "v", "$$id.patientIds" }
                                                }
                                            }
                                        }
                                    }
                                }
                            })
                        }
                    })
                },
                {
                    "historicalLocations", new BsonDocument("$cond", new BsonDocument
                    {
                        { "if", new BsonDocument("$not", new BsonArray { new BsonDocument("$isArray", "$historicalLocations") }) },
                        { "then", "$historicalLocations" },
                        {
                            "else", new BsonDocument("$arrayToObject", new BsonArray
                            {
                                new BsonDocument
                                {
                                    {
                                        "$map", new BsonDocument
                                        {
                                            { "input", "$historicalLocations" },
                                            { "as", "location" },
                                            {
                                                "in", new BsonDocument
                                                {
                                                    {
                                                        "k", new BsonDocument("$dateToString", new BsonDocument
                                                        {
                                                            { "format", "%Y-%m-%dT%H:%M:%S.%LZ" },
                                                            { "date", "$$location.admTime" }
                                                        })
                                                    },
                                                    { "v", "$$location.patientLocation" }
                                                }
                                            }
                                        }
                                    }
                                }
                            })
                        }
                    })
                }
            }),
            new BsonDocument("$merge", new BsonDocument
            {
                { "into", "admissions" },
                { "whenMatched", "replace" },
                { "whenNotMatched", "discard" }
            })
        };

        collectionAdm.Aggregate<BsonDocument>(pipelineAdm).ToList();
         var collectionArcP = Database.GetCollection<BsonDocument>("archive_patient");

        var pipelineArcP = new[]
        {
            new BsonDocument("$addFields", new BsonDocument
            {
                {
                    "person.historicalIds", new BsonDocument("$cond", new BsonDocument
                    {
                        // si ya es document → no tocar
                        { "if", new BsonDocument("$not", new BsonArray { new BsonDocument("$isArray", "$person.historicalIds") }) },
                        { "then", "$person.historicalIds" },
                        // si es array → revertir
                        {
                            "else", new BsonDocument("$arrayToObject", new BsonArray
                            {
                                new BsonDocument
                                {
                                    {
                                        "$map", new BsonDocument
                                        {
                                            { "input", "$person.historicalIds" },
                                            { "as", "id" },
                                            {
                                                "in", new BsonDocument
                                                {
                                                    {
                                                        "k", new BsonDocument("$dateToString", new BsonDocument
                                                        {
                                                            { "format", "%Y-%m-%dT%H:%M:%S.%LZ" },
                                                            { "date", "$$id.time" }
                                                        })
                                                    },
                                                    { "v", "$$id.patientIds" }
                                                }
                                            }
                                        }
                                    }
                                }
                            })
                        }
                    })
                },
                {
                    "historicalLocations", new BsonDocument("$cond", new BsonDocument
                    {
                        { "if", new BsonDocument("$not", new BsonArray { new BsonDocument("$isArray", "$historicalLocations") }) },
                        { "then", "$historicalLocations" },
                        {
                            "else", new BsonDocument("$arrayToObject", new BsonArray
                            {
                                new BsonDocument
                                {
                                    {
                                        "$map", new BsonDocument
                                        {
                                            { "input", "$historicalLocations" },
                                            { "as", "location" },
                                            {
                                                "in", new BsonDocument
                                                {
                                                    {
                                                        "k", new BsonDocument("$dateToString", new BsonDocument
                                                        {
                                                            { "format", "%Y-%m-%dT%H:%M:%S.%LZ" },
                                                            { "date", "$$location.admTime" }
                                                        })
                                                    },
                                                    { "v", "$$location.patientLocation" }
                                                }
                                            }
                                        }
                                    }
                                }
                            })
                        }
                    })
                }
            }),
            new BsonDocument("$merge", new BsonDocument
            {
                { "into", "archive_patient" },
                { "whenMatched", "replace" },
                { "whenNotMatched", "discard" }
            })
        };

        collectionArcP.Aggregate<BsonDocument>(pipelineArcP).ToList();
    }
}
