using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
public DateTime OrderDate { get; set; }
public string OrderNumber { get; set; }
public string ItemDescription { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
public string ShipTo { get; set; }
public bool IsMedical { get; set; }
public override string ToString()
return $"{OrderDate:yyyy-MM-dd},{OrderNumber},{ItemDescription},{Quantity},{Price:F2},{ShipTo},{(IsMedical ? "Y" : "N")}";
Console.WriteLine("Amazon Order Parser - Starting...");
Console.WriteLine("Looking for order files in: " + Directory.GetCurrentDirectory());
string[] inputFiles = Directory.GetFiles(".", "*.*")
file.EndsWith(".csv", StringComparison.OrdinalIgnoreCase) ||
file.EndsWith(".txt", StringComparison.OrdinalIgnoreCase) ||
file.EndsWith(".md", StringComparison.OrdinalIgnoreCase))
Console.WriteLine($"Found {inputFiles.Length} potential files to process.");
List<AmazonOrder> allOrders = new List<AmazonOrder>();
foreach (string file in inputFiles)
string[] lines = File.ReadAllLines(file);
if (lines.Length > 0 && IsOrderFileHeader(lines[0]))
var orders = ParseOrderFile(lines);
allOrders.AddRange(orders);
Console.WriteLine($"Processed {orders.Count} orders from {Path.GetFileName(file)}");
Console.WriteLine($"No valid orders found in {Path.GetFileName(file)}");
Console.WriteLine($"Skipping {Path.GetFileName(file)} - not recognized as an order file");
Console.WriteLine($"Error processing {Path.GetFileName(file)}: {ex.Message}");
if (allOrders.Count == 0)
Console.WriteLine("No orders were found. Please check that your files contain Amazon order data.");
Console.WriteLine("Press any key to exit...");
var sortedOrders = allOrders
.OrderByDescending(o => o.OrderDate)
.ThenBy(o => o.OrderNumber)
string outputFile = "combined_amazon_orders.csv";
WriteOrdersToFile(sortedOrders, outputFile);
Console.WriteLine($"Successfully combined {sortedOrders.Count} orders into {outputFile}");
GenerateStatistics(sortedOrders);
Console.WriteLine("\nProcess completed successfully!");
Console.WriteLine("Press any key to exit...");
Console.WriteLine($"Unexpected error: {ex.Message}");
Console.WriteLine(ex.StackTrace);
Console.WriteLine("Press any key to exit...");
static bool IsOrderFileHeader(string line)
return line.Contains("order date") &&
(line.Contains("order #") || line.Contains("order number")) &&
(line.Contains("item description") || line.Contains("description")) &&
(line.Contains("ship to") || line.Contains("shipto") || line.Contains("ship"));
static List<AmazonOrder> ParseOrderFile(string[] lines)
var orders = new List<AmazonOrder>();
for (int i = 1; i < lines.Length; i++)
string line = lines[i].Trim();
if (string.IsNullOrEmpty(line)) continue;
var order = ParseOrderLine(line);
Console.WriteLine($"Error parsing line {i}: {ex.Message}");
static AmazonOrder ParseOrderLine(string line)
string[] parts = SplitCSVLine(line);
if (parts.Length < 5) return null;
DateTime orderDate = ParseOrderDate(parts[0]);
string orderNumber = parts[1].Trim();
string itemDescription = parts[2].Trim();
if (parts.Length > 3 && !string.IsNullOrEmpty(parts[3]))
int.TryParse(parts[3].Trim(), out quantity);
if (quantity <= 0) quantity = 1;
if (parts.Length > 4 && !string.IsNullOrEmpty(parts[4]))
string priceText = parts[4].Trim();
if (priceText.StartsWith("$"))
priceText = priceText.Substring(1);
decimal.TryParse(priceText, NumberStyles.Currency, CultureInfo.InvariantCulture, out price);
string shipTo = parts.Length > 5 ? parts[5].Trim() : "";
string medicalText = parts[6].Trim().ToUpper();
isMedical = medicalText == "Y" || medicalText == "YES" || medicalText == "TRUE";
OrderNumber = orderNumber,
ItemDescription = itemDescription,
static DateTime ParseOrderDate(string dateText)
dateText = dateText.Trim();
if (DateTime.TryParse(dateText, out DateTime result))
foreach (string format in formats)
if (DateTime.TryParseExact(dateText, format, CultureInfo.InvariantCulture,
DateTimeStyles.None, out result))
Regex monthDayYearRegex = new Regex(@"(\w+)\s+(\d+)\s+(\d{4})");
Match match = monthDayYearRegex.Match(dateText);
string month = match.Groups[1].Value;
string day = match.Groups[2].Value;
string year = match.Groups[3].Value;
string reformattedDate = $"{month} {day}, {year}";
if (DateTime.TryParse(reformattedDate, out result))
Console.WriteLine($"Could not parse date: {dateText}");
static string[] SplitCSVLine(string line)
List<string> result = new List<string>();
StringBuilder field = new StringBuilder();
else if (c == ',' && !inQuotes)
result.Add(field.ToString());
result.Add(field.ToString());
static void WriteOrdersToFile(List<AmazonOrder> orders, string filename)
using (StreamWriter writer = new StreamWriter(filename))
writer.WriteLine("OrderDate,OrderNumber,ItemDescription,Quantity,Price,ShipTo,Medical");
foreach (var order in orders)
writer.WriteLine(order.ToString());
static void GenerateStatistics(List<AmazonOrder> orders)
decimal totalSpending = orders.Sum(o => o.Price);
decimal medicalSpending = orders.Where(o => o.IsMedical).Sum(o => o.Price);
decimal nonMedicalSpending = orders.Where(o => !o.IsMedical).Sum(o => o.Price);
var ordersByMonth = orders
.GroupBy(o => new { o.OrderDate.Year, o.OrderDate.Month })
YearMonth = $"{g.Key.Year}-{g.Key.Month:D2}",
Total = g.Sum(o => o.Price)
.OrderByDescending(x => x.YearMonth)
var ordersByRecipient = orders
Total = g.Sum(o => o.Price)
.OrderByDescending(x => x.Count)
using (StreamWriter writer = new StreamWriter("amazon_order_statistics.txt"))
writer.WriteLine("Amazon Order Statistics");
writer.WriteLine("=======================");
writer.WriteLine($"Total Orders: {orders.Count}");
writer.WriteLine($"Total Spending: ${totalSpending:F2}");
writer.WriteLine($"Medical Spending: ${medicalSpending:F2} ({medicalSpending / totalSpending:P1})");
writer.WriteLine($"Non-Medical Spending: ${nonMedicalSpending:F2} ({nonMedicalSpending / totalSpending:P1})");
writer.WriteLine("Orders by Month");
writer.WriteLine("--------------");
foreach (var month in ordersByMonth)
writer.WriteLine($"{month.YearMonth}: {month.Count} orders, ${month.Total:F2}");
writer.WriteLine("Orders by Recipient");
writer.WriteLine("-------------------");
foreach (var recipient in ordersByRecipient)
writer.WriteLine($"{recipient.Recipient}: {recipient.Count} orders, ${recipient.Total:F2}");
.GroupBy(o => o.ItemDescription)
Total = g.Sum(o => o.Price)
.OrderByDescending(x => x.Count)
writer.WriteLine("Most Commonly Ordered Items");
writer.WriteLine("--------------------------");
foreach (var item in commonItems)
writer.WriteLine($"{item.Item}: {item.Count} orders, ${item.Total:F2}");
var expensiveItems = orders
.GroupBy(o => o.ItemDescription)
Total = g.Sum(o => o.Price),
AveragePrice = g.Average(o => o.Price)
.OrderByDescending(x => x.AveragePrice)
writer.WriteLine("Most Expensive Items");
writer.WriteLine("--------------------");
foreach (var item in expensiveItems)
writer.WriteLine($"{item.Item}: ${item.AveragePrice:F2} avg, {item.Count} orders");
writer.WriteLine("Monthly Spending Trend");
writer.WriteLine("---------------------");
foreach (var month in ordersByMonth)
decimal medicalTotal = orders
.Where(o => o.IsMedical &&
o.OrderDate.Year == int.Parse(month.YearMonth.Split('-')[0]) &&
o.OrderDate.Month == int.Parse(month.YearMonth.Split('-')[1]))
decimal nonMedicalTotal = month.Total - medicalTotal;
writer.WriteLine($"{month.YearMonth}: ${month.Total:F2} total (Medical: ${medicalTotal:F2}, Non-Medical: ${nonMedicalTotal:F2})");
Console.WriteLine("Statistics written to amazon_order_statistics.txt");