using System;
using System.IO;
namespace ytLive.Helpers;
///
/// Which run of LlamaCasty this process is, and where its private state lives.
/// Dev-only affordance (creator directive, 2026-09-26). Pre-1.0 the creator
/// needs two instances side by side: one streaming, one screen-capturing the other.
/// Two instances on one Windows profile collide on state, and two of those collisions
/// are hard failures rather than annoyances:
///
/// - The SQLite layout DB. The app's model is read-whole-scene / write-whole-scene,
/// so two instances saving different layouts clobber each other.
/// - The WebView2 user data folder. Chromium takes an exclusive lock on it; the
/// second instance of the same exe simply fails to start.
/// - The auth token store. A test instance would overwrite the real YouTube
/// sign-in.
/// - startup.log. Two appenders interleave into one file, so a crash in either
/// instance is ambiguous.
///
/// So in DEBUG a process can claim an identity and gets its own private root
/// under instances\<id>: $env:YTLIVE_INSTANCE=2; dotnet run.
/// Recording, screen capture and the ffmpeg tools\ cache are deliberately LEFT
/// shared — the cache should be shared, and the creator chooses the record folder.
/// Global hotkeys are also left alone: if both instances register the same one, Windows
/// refuses the second, which is the correct answer.
/// At 1.0 this disappears. The whole implementation is inside
/// #if DEBUG; a Release build compiles to the two pass-throughs at the bottom —
/// no environment variable, no alternate folder, not even the variable's NAME in the
/// binary. Call sites are unconditional, so Release cannot accidentally diverge: it
/// always resolves the one real user profile.
///
public static class InstanceProfile
{
#if DEBUG
/// Environment variable naming this instance. Absent or blank = the primary
/// instance on the real user profile.
public const string InstanceVariable = "YTLIVE_INSTANCE";
/// This instance's id, or null for the primary instance.
public static string? Id => Sanitize(Environment.GetEnvironmentVariable(InstanceVariable));
/// Private state root: the real profile normally, a per-instance subfolder
/// when an id is claimed.
public static string DataRoot => Id is { } id
? Path.Combine(DefaultRoot, "instances", id)
: DefaultRoot;
/// Chromium's user data folder, or null to let WebView2 pick its default
/// (which is what Release always does). Must be per-instance or the second
/// instance dies on Chromium's exclusive lock.
public static string? WebViewDataFolder => Id is null ? null : Path.Combine(DataRoot, "webview2");
/// Reject anything that is not a plain path segment, so the variable can
/// never be used to walk out of the profile directory or name a UNC path.
private static string? Sanitize(string? raw)
{
if (string.IsNullOrWhiteSpace(raw)) return null;
var trimmed = raw.Trim();
foreach (var c in trimmed)
if (!char.IsLetterOrDigit(c) && c != '-' && c != '_') return null;
return trimmed;
}
#else
// Release: one profile, no alternate paths, no environment variable. Multi-instance
// is a development affordance, not a shipping feature.
public static string DataRoot => DefaultRoot;
public static string? WebViewDataFolder => null;
#endif
/// The one real user profile: %APPDATA%\ytLlive. Note the historical
/// double-L — do not "fix" it, users already have their layouts there.
public static string DefaultRoot => Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"ytLlive");
}