using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.IO;
using System.Net;
using Newtonsoft.Json.Linq;

namespace ValidateReceipt.iOS
{
    public class ValidateIosReceipt : System.Web.UI.Page
    {
        private StreamWriter sw;
        private const string liveUrl = "https://buy.itunes.apple.com/verifyReceipt";
        private const string sandboxUrl = "https://sandbox.itunes.apple.com/verifyReceipt";
        private const bool usingSandbox = true;

        protected void Page_Load(object sender, EventArgs e)
        {
            string status = "";
            try
            {
                string itemID = Request["itemid"];

                string filePath = Server.MapPath("~/" + DateTime.Now.ToString("MMddyy_hhmm") +"_Receipt" + itemID + ".txt");
                FileStream fs = new FileStream(filePath, FileMode.Create);
                sw = new StreamWriter(fs);

                if (Request.Files.Count > 0)
                {
                    HttpPostedFile file = Request.Files[0];
                    Stream fileStream;
                    byte[] fileByte = new byte[file.ContentLength];
                    fileStream = file.InputStream;
                    fileStream.Read(fileByte, 0, file.ContentLength);
                    string receiptData = Encoding.ASCII.GetString(fileByte);

                    sw.Write(receiptData);

                    PurchaseItem(itemID, receiptData, usingSandbox);
                }
            }
            catch (Exception ex)
            {
                status = "Error: " + ex.Message + ex.StackTrace;
                sw.Write(Environment.NewLine + status);
            }

            sw.Close();
            
            Response.Clear();
            Response.ContentType = "text/xml";
            Response.ContentEncoding = Encoding.UTF8;
            Response.Write(status);
            Response.End();
        }

        public static bool PurchaseItem(string itemID, string receiptData, bool sandbox)
        {
            // Verify the receipt with Apple
            string postString = String.Format("{{ \"receipt-data\" : \"{0}\" }}", receiptData);
            ASCIIEncoding ascii = new ASCIIEncoding();
            byte[] postBytes = ascii.GetBytes(postString);
            HttpWebRequest request;
            if (sandbox)
            {
                request = WebRequest.Create(sandboxUrl) as HttpWebRequest;
            }
            else
            {
                request = WebRequest.Create(liveUrl) as HttpWebRequest;
            }
            request.Method = "POST";
            request.ContentType = "application/json";
            request.ContentLength = postBytes.Length;
            Stream postStream = request.GetRequestStream();
            postStream.Write(postBytes, 0, postBytes.Length);
            postStream.Close();
            HttpWebResponse response = request.GetResponse() as HttpWebResponse;
            StringBuilder sb = new StringBuilder();
            byte[] buf = new byte[8192];
            Stream resStream = response.GetResponseStream();
            string tempString = null;
            int count = 0;
            do
            {
                count = resStream.Read(buf, 0, buf.Length);
                if (count != 0)
                {
                    tempString = Encoding.ASCII.GetString(buf, 0, count);
                    sb.Append(tempString);
                }
            }
            while (count > 0);

            if (!sandbox)
            {
                var fd = JObject.Parse(sb.ToString());

                // Receipt not valid
                if (fd["status"].ToString() == "21007")
                {
                    // this is a sandbox receipt
                    return PurchaseItem(itemID, receiptData, true);
                }
            }

            return ValidateReceipt(itemID, sb.ToString());
        }

        private static bool ValidateReceipt(string itemID, string Response)
        {
            var fd = JObject.Parse(Response);

            // Receipt not valid
            if (fd["status"].ToString() != "0")
            {
                throw new Exception("The receipt is invalid - status = " + fd["status"].ToString());
            }

            var receipt = fd["receipt"];
            if (receipt == null)
            {
                throw new Exception("The receipt is empty.");
            }
            if (receipt["in_app"] != null)
            {
                var inApp = receipt["in_app"][0];
                // Product ID does not match what we expected
                if (String.Compare(inApp["product_id"].ToString().Replace("\"", "").Trim(), itemID.Trim(), true) != 0)
                {
                    throw new Exception("The receipt is for the wrong item.");
                }

                // This product was not sold by the right app
                if (String.Compare(receipt["bundle_id"].ToString().Replace("\"", "").Trim(), "com.gusinc.ShowMeQRmgr", true) != 0)
                {
                    throw new Exception("The receipt is for the wrong app.");
                }

                // This transaction didn't occur within 24 hours in either direction; somebody is reusing a receipt
                DateTime transDate = DateTime.SpecifyKind(DateTime.Parse(inApp["purchase_date"].ToString().Replace("\"", "").Replace("Etc/GMT", "")), DateTimeKind.Utc);
                TimeSpan delay = DateTime.UtcNow - transDate;
                if (delay.TotalHours > 24 || delay.TotalHours < -24)
                {
                    throw new Exception("The receipt is invalid - it is being reused.");
                }
            }
            else
            {
                // Product ID does not match what we expected
                if (String.Compare(receipt["product_id"].ToString().Replace("\"", "").Trim(), itemID.Trim(), true) != 0)
                {
                    throw new Exception("The receipt is for the wrong item.");
                }

                // This product was not sold by the right app
                if (String.Compare(receipt["bid"].ToString().Replace("\"", "").Trim(), "com.gusinc.ShowMeQRmgr", true) != 0)
                {
                    throw new Exception("The receipt is for the wrong app.");
                }

                // This transaction didn't occur within 24 hours in either direction; somebody is reusing a receipt
                DateTime transDate = DateTime.SpecifyKind(DateTime.Parse(receipt["purchase_date"].ToString().Replace("\"", "").Replace("Etc/GMT", "")), DateTimeKind.Utc);
                TimeSpan delay = DateTime.UtcNow - transDate;
                if (delay.TotalHours > 24 || delay.TotalHours < -24)
                {
                    throw new Exception("The receipt is invalid - it is being reused.");
                }
            }

            return true;
        }

    }
}