using System;
using System.IO;
using System.Linq;
using Microsoft.Extensions.Configuration;
namespace Sozsoft.Platform.Data.Seeds;
///
/// Runtime'da duzenlenebilen seed dosyalarinin klasorunu cozer.
///
/// Kod ile birlikte versiyonlanan sabit seed'ler (DbMigrator projesindeki *Data.json dosyalari)
/// buraya dahil degildir; onlar kendi projelerinin ciktisinda kalir.
///
///
/// Klasor bilincli olarak hicbir projenin icinde degildir: depoda configs/seeds altinda durur ve
/// konteynere bind mount ile baglanir. Boylece bir seed dosyasi degistiginde ne api ne de migrator
/// imaji yeniden derlenir; deploy sirasindaki git pull yeterlidir. Ayni klasor File Manager
/// uzerinden de duzenlenebildigi icin yapilan degisiklik dogrudan host diskinde kalici olur.
///
///
/// Klasor duzeni CDN ile ayni kapsam mantigini izler — once kapsam, sonra icerik turu:
///
/// seeds/
/// host/ → host (varsayilan) veritabani kapsami
/// crud/
/// wizard/
/// data/
/// sql/ → SQL Server saglayicisi
/// object/ → nesne olusturulur/guncellenir
/// execute/ → nesne olusturulur, ayrica tum migration'lar bitince calistirilir
/// postgres/ → PostgreSQL saglayicisi
/// object/
/// execute/
/// tenants/
/// {tenantId}/ → her tenant kendi klasorunde
/// crud/ wizard/ data/ sql/{object,execute}/ postgres/{object,execute}/
///
///
///
/// Cozum sirasi:
/// 1) App:SeedsPath ayari (konteynerde mount noktasi),
/// 2) calisma dizininden yukari dogru configs/seeds aramasi (local gelistirme),
/// 3) calisma dizininin altindaki Seeds klasoru (son care).
///
///
public static class SeedPathResolver
{
public const string ConfigurationKey = "App:SeedsPath";
/// Host veritabani kapsamindaki seed'lerin kok klasoru.
public const string HostFolder = "host";
/// Tenant kapsamindaki seed'lerin kok klasoru; altinda tenant Id'si ile klasorler bulunur.
public const string TenantsFolder = "tenants";
/// SQL Server saglayicisinin script klasoru.
public const string SqlFolder = "sql";
/// PostgreSQL saglayicisinin script klasoru.
public const string PostgresFolder = "postgres";
/// Yalnizca olusturulan/guncellenen nesne scriptleri.
public const string ObjectFolder = "object";
/// Olusturulan, ayrica tum migration'lar bittikten sonra calistirilan scriptler.
public const string ExecuteFolder = "execute";
/// Wizard'in urettigi konfigurasyon dosyalari.
public const string WizardFolder = "wizard";
/// Crud endpoint konfigurasyon dosyalari.
public const string CrudFolder = "crud";
/// Liste verisinin aynalandigi seed dosyalari (data/{ListFormCode}.json).
public const string DataFolder = "data";
/// Bir ListForm icin varsayilan veri seed dosyasinin kapsam klasorune gore goreli yolu.
public static string GetDataFilePath(string listFormCode)
{
return $"{DataFolder}/{listFormCode}.json";
}
private const string RepositorySeedsFolder = "seeds";
private const string RepositoryConfigsFolder = "configs";
private const string FallbackFolderName = "Seeds";
/// Seed kok klasorunun tam yolunu dondurur. Klasorun var olmasi garanti edilmez.
public static string GetRootPath(IConfiguration? configuration)
{
var configuredPath = configuration?[ConfigurationKey];
if (!string.IsNullOrWhiteSpace(configuredPath))
{
return Path.GetFullPath(configuredPath);
}
var repositoryPath = FindRepositorySeedsPath();
if (repositoryPath != null)
{
return repositoryPath;
}
return Path.Combine(Directory.GetCurrentDirectory(), FallbackFolderName);
}
/// Seed kok klasorunun altindaki bir alt yolu dondurur.
public static string GetPath(IConfiguration? configuration, params string[] subPaths)
{
var path = GetRootPath(configuration);
foreach (var subPath in subPaths)
{
path = Path.Combine(path, subPath);
}
return path;
}
///
/// Kapsam klasorunun (host ya da ilgili tenant) altindaki yolu dondurur.
/// null ise host/, aksi halde tenants/{tenantId}/ kullanilir.
///
public static string GetScopePath(IConfiguration? configuration, Guid? tenantId, params string[] subPaths)
{
return GetPath(configuration, BuildScopeSubPaths(tenantId, subPaths));
}
/// Kapsam klasorunun seed koküne gore goreli adi (host ya da tenants/{tenantId}).
public static string GetScopeFolderName(Guid? tenantId)
{
return tenantId == null
? HostFolder
: $"{TenantsFolder}/{tenantId.Value}";
}
/// Aktif veritabani saglayicisina karsilik gelen script klasorunun adi.
public static string GetProviderFolderName(bool isPostgreSql)
{
return isPostgreSql ? PostgresFolder : SqlFolder;
}
private static string[] BuildScopeSubPaths(Guid? tenantId, string[] subPaths)
{
var scopeSegments = tenantId == null
? new[] { HostFolder }
: new[] { TenantsFolder, tenantId.Value.ToString() };
return scopeSegments.Concat(subPaths ?? Array.Empty()).ToArray();
}
/// Calisma dizininden yukari dogru cikarak depodaki configs/seeds klasorunu arar.
private static string? FindRepositorySeedsPath()
{
var dir = new DirectoryInfo(Directory.GetCurrentDirectory());
while (dir != null)
{
var candidate = Path.Combine(dir.FullName, RepositoryConfigsFolder, RepositorySeedsFolder);
if (Directory.Exists(candidate))
{
return candidate;
}
dir = dir.Parent;
}
return null;
}
}