#!/usr/bin/env python3
"""Deterministic, standard-library cleaner for this synthetic order demo."""

import csv
import re
import sys
from datetime import datetime
from decimal import Decimal, InvalidOperation
from pathlib import Path

COLUMNS = [
    "order_id", "customer_name", "email", "order_date", "amount", "status",
    "country", "notes", "sku", "quantity", "unit_price", "shipping_fee",
    "tax_amount", "payment_method", "currency", "sales_channel", "phone",
    "postal_code", "city", "shipping_method", "gift_flag", "priority",
    "tracking_code", "customer_type",
]
DATE_FORMATS = ("%m/%d/%Y", "%Y-%m-%d", "%d %b %Y", "%Y/%m/%d", "%m-%d-%Y", "%m/%d/%y")
STATUSES = {
    "paid": "Paid", "pending": "Pending", "pendng": "Pending",
    "processing": "Processing", "shipped": "Shipped", "in transit": "In Transit",
    "completed": "Completed", "complete": "Completed", "cancelled": "Cancelled",
    "canceled": "Cancelled", "refunded": "Refunded",
}
COUNTRIES = {
    "us": "United States", "usa": "United States", "united states": "United States",
    "untied states": "United States", "ca": "Canada", "canada": "Canada",
    "uk": "United Kingdom", "united kingdom": "United Kingdom",
    "es": "Spain", "spain": "Spain", "de": "Germany", "germany": "Germany",
    "jp": "Japan", "japan": "Japan", "pt": "Portugal", "portugal": "Portugal",
    "in": "India", "india": "India",
}
PAYMENT_METHODS = {
    "card": "Card", "credit card": "Card", "paypal": "PayPal",
    "bank transfer": "Bank Transfer", "bank xfer": "Bank Transfer", "cash": "Cash",
}
SALES_CHANNELS = {
    "online": "Online", "web": "Online", "marketplace": "Marketplace",
    "market place": "Marketplace", "store": "Store", "in store": "Store",
}
SHIPPING_METHODS = {
    "ground": "Ground", "express": "Express", "expres": "Express",
    "pickup": "Pickup", "pick up": "Pickup",
}
GIFT_FLAGS = {"y": "Yes", "yes": "Yes", "true": "Yes", "n": "No", "no": "No", "false": "No"}
PRIORITIES = {"std": "Standard", "standard": "Standard", "rush": "Rush"}
CUSTOMER_TYPES = {"retail": "Retail", "wholesale": "Wholesale", "subscriber": "Subscriber"}


def mapped(value, choices, field, allow_blank=False):
    key = " ".join(value.lower().split())
    if not key and allow_blank:
        return ""
    if key not in choices:
        raise ValueError(f"Unknown {field}: {value!r}")
    return choices[key]


def date_value(value):
    for pattern in DATE_FORMATS:
        try:
            return datetime.strptime(value, pattern).date().isoformat()
        except ValueError:
            pass
    raise ValueError(f"Unrecognized date: {value!r}")


def money_value(value):
    value = value.strip()
    if value.startswith("USD "):
        value = value[4:]
    elif value.startswith("$"):
        value = value[1:]
    value = value.replace(",", "")
    if not re.fullmatch(r"\d+(?:\.\d{1,2})?", value):
        raise ValueError(f"Ambiguous or unrecognized USD amount: {value!r}")
    try:
        return f"{Decimal(value):.2f}"
    except InvalidOperation as exc:
        raise ValueError(f"Invalid amount: {value!r}") from exc


def phone_value(value, country):
    if not value:
        return ""
    if country not in {"United States", "Canada"}:
        raise ValueError("Only synthetic US/Canada sample phones have a documented normalization rule")
    if not re.fullmatch(r"[+0-9()\s-]+", value):
        raise ValueError(f"Unrecognized phone characters: {value!r}")
    digits = re.sub(r"\D", "", value)
    if len(digits) == 10:
        digits = "1" + digits
    if len(digits) != 11 or not digits.startswith("1"):
        raise ValueError(f"Unrecognized phone: {value!r}")
    return "+" + digits


def clean_row(source):
    if None in source or any(value is None for value in source.values()):
        raise ValueError("Malformed row or wrong number of columns")
    row = {key: source[key].strip() for key in COLUMNS}
    row["order_id"] = re.sub(r"\s+", "", row["order_id"]).upper()
    row["customer_name"] = " ".join(row["customer_name"].split()).title()
    row["email"] = row["email"].lower()
    row["order_date"] = date_value(row["order_date"])
    for field in ("amount", "unit_price", "shipping_fee", "tax_amount"):
        row[field] = money_value(row[field])
    row["status"] = mapped(row["status"], STATUSES, "status")
    row["country"] = mapped(row["country"], COUNTRIES, "country")
    row["sku"] = re.sub(r"\s+", "", row["sku"]).upper()
    if not re.fullmatch(r"\d+", row["quantity"]):
        raise ValueError(f"Unrecognized quantity: {row['quantity']!r}")
    row["quantity"] = str(int(row["quantity"]))
    row["payment_method"] = mapped(row["payment_method"], PAYMENT_METHODS, "payment method")
    row["currency"] = mapped(row["currency"], {"usd": "USD", "us dollars": "USD", "$": "USD"}, "currency")
    row["sales_channel"] = mapped(row["sales_channel"], SALES_CHANNELS, "sales channel")
    row["phone"] = phone_value(row["phone"], row["country"])
    row["postal_code"] = " ".join(row["postal_code"].upper().split())
    row["city"] = " ".join(row["city"].split()).title()
    row["shipping_method"] = mapped(row["shipping_method"], SHIPPING_METHODS, "shipping method")
    row["gift_flag"] = mapped(row["gift_flag"], GIFT_FLAGS, "gift flag", allow_blank=True)
    row["priority"] = mapped(row["priority"], PRIORITIES, "priority", allow_blank=True)
    row["tracking_code"] = re.sub(r"\s+", "", row["tracking_code"]).upper()
    row["customer_type"] = mapped(row["customer_type"], CUSTOMER_TYPES, "customer type")
    return row


def main(source, destination):
    with open(source, encoding="utf-8-sig", newline="") as file:
        reader = csv.DictReader(file)
        if reader.fieldnames != COLUMNS:
            raise ValueError(f"Unexpected columns: {reader.fieldnames!r}")
        cleaned = [clean_row(source_row) for source_row in reader]
    seen = set()
    unique = []
    for row in cleaned:
        if row["order_id"] not in seen:
            seen.add(row["order_id"])
            unique.append(row)
    with open(destination, "w", encoding="utf-8", newline="") as file:
        writer = csv.DictWriter(file, fieldnames=COLUMNS, lineterminator="\n")
        writer.writeheader()
        writer.writerows(unique)


if __name__ == "__main__":
    if len(sys.argv) != 3:
        raise SystemExit("Usage: python clean_demo.py raw.csv cleaned.csv")
    main(Path(sys.argv[1]), Path(sys.argv[2]))
