using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Themes;
namespace AxCopilot.Handlers;
///
/// 날짜/시간 변환기 핸들러. "date" 프리픽스로 사용합니다.
/// 예: date → 현재 날짜/시간 + 유닉스 타임스탬프
/// date +30d → 오늘 + 30일
/// date -100d → 오늘 - 100일
/// date 2026-12-25 → 해당 날짜까지 D-day + 요일
/// date 1711584000 → 유닉스 타임스탬프 → 날짜
/// date to unix → 현재 시각의 유닉스 타임스탬프
/// Enter → 결과를 클립보드에 복사.
///
public class DateCalcHandler : IActionHandler
{
public string? Prefix => "date";
public PluginMetadata Metadata => new(
"DateCalc",
"날짜 계산 · D-day · 타임스탬프 변환",
"1.0",
"AX");
private static readonly string[] DateFormats =
["yyyy-MM-dd", "yyyy/MM/dd", "yyyyMMdd", "MM/dd/yyyy", "dd-MM-yyyy"];
public Task> GetItemsAsync(string query, CancellationToken ct)
{
var q = query.Trim();
var now = DateTime.Now;
var items = new List();
if (string.IsNullOrWhiteSpace(q))
{
// 현재 날짜/시간 정보
var dayName = now.ToString("dddd", new CultureInfo("ko-KR"));
items.Add(Item($"{now:yyyy-MM-dd} ({dayName})", $"{now:HH:mm:ss} · {now:yyyy-MM-dd}"));
items.Add(Item($"유닉스 타임스탬프: {new DateTimeOffset(now).ToUnixTimeSeconds()}", "현재 시각의 Unix epoch"));
items.Add(Item($"올해 {now.DayOfYear}일째 / 남은 일: {(new DateTime(now.Year, 12, 31) - now).Days}일",
$"ISO 주차: {ISOWeek.GetWeekOfYear(now)}주"));
return Task.FromResult>(items);
}
// +30d / -100d 패턴
var offsetMatch = Regex.Match(q, @"^([+-])(\d+)([dDwWmMyY])$");
if (offsetMatch.Success)
{
var sign = offsetMatch.Groups[1].Value == "+" ? 1 : -1;
var val = int.Parse(offsetMatch.Groups[2].Value) * sign;
var unit = offsetMatch.Groups[3].Value.ToLowerInvariant();
var target = unit switch
{
"d" => now.AddDays(val),
"w" => now.AddDays(val * 7),
"m" => now.AddMonths(val),
"y" => now.AddYears(val),
_ => now
};
var dayName = target.ToString("dddd", new CultureInfo("ko-KR"));
var diff = (target.Date - now.Date).Days;
var diffStr = diff >= 0 ? $"오늘로부터 {diff}일 후" : $"오늘로부터 {Math.Abs(diff)}일 전";
items.Add(Item($"{target:yyyy-MM-dd} ({dayName})", diffStr));
return Task.FromResult>(items);
}
// 유닉스 타임스탬프 (10자리 또는 13자리 숫자)
if (Regex.IsMatch(q, @"^\d{10,13}$") && long.TryParse(q, out long epoch))
{
var ts = epoch > 9_999_999_999 ? epoch / 1000 : epoch; // 밀리초→초
var dt = DateTimeOffset.FromUnixTimeSeconds(ts).LocalDateTime;
var dayName = dt.ToString("dddd", new CultureInfo("ko-KR"));
items.Add(Item($"{dt:yyyy-MM-dd HH:mm:ss} ({dayName})", $"Unix {epoch} → 로컬 시간"));
return Task.FromResult>(items);
}
// "to unix" / "unix" 키워드
if (q.Equals("unix", StringComparison.OrdinalIgnoreCase) ||
q.Equals("to unix", StringComparison.OrdinalIgnoreCase))
{
var unix = new DateTimeOffset(now).ToUnixTimeSeconds();
items.Add(Item($"{unix}", $"현재 시각 ({now:yyyy-MM-dd HH:mm:ss}) → Unix 타임스탬프"));
return Task.FromResult>(items);
}
// 날짜 파싱 → D-day 계산
if (DateTime.TryParseExact(q, DateFormats, CultureInfo.InvariantCulture,
DateTimeStyles.None, out var parsed))
{
var dayName = parsed.ToString("dddd", new CultureInfo("ko-KR"));
var diff = (parsed.Date - now.Date).Days;
var dday = diff switch
{
0 => "오늘",
> 0 => $"D-{diff} (앞으로 {diff}일)",
_ => $"D+{Math.Abs(diff)} ({Math.Abs(diff)}일 지남)"
};
items.Add(Item($"{parsed:yyyy-MM-dd} ({dayName})", dday));
return Task.FromResult>(items);
}
items.Add(new LauncherItem(
"날짜 형식을 인식할 수 없습니다",
"예: +30d, -100d, 2026-12-25, 1711584000, unix",
null, null, Symbol: Symbols.Warning));
return Task.FromResult>(items);
}
private static LauncherItem Item(string title, string subtitle) =>
new(title, $"{subtitle} · Enter로 복사", null, title, Symbol: Symbols.Clock);
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
{
if (item.Data is string text && !string.IsNullOrWhiteSpace(text))
{
try { Application.Current?.Dispatcher.Invoke(() => Clipboard.SetText(text)); }
catch { }
}
return Task.CompletedTask;
}
}