using System;
using System.Configuration;
using System.Linq;
using System.Net.Mail;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.WebPages;

public class CommentHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        Post post = Storage.GetAllPosts().SingleOrDefault(p => p.ID == context.Request["postId"]);

        if (post == null)
            throw new HttpException(404, "The post does not exist");

        string mode = context.Request["mode"];

        if (mode == "save" && context.Request.HttpMethod == "POST" && post.AreCommentsOpen(new HttpContextWrapper(context)) && Blog.MatchesUniqueId(context))
        {
            Save(context, post);
        }
        else if (mode == "delete")
        {
            Delete(context, post);
        }
        else if (mode == "approve")
        {
            Approve(context, post);
        }
    }

    private static void Save(HttpContext context, Post post)
    {
        string name = context.Request.Form["name"];
        string email = context.Request.Form["email"];
        string website = context.Request.Form["website"];
        string content = context.Request.Form["content"];

        Validate(name, email, content);

        Comment comment = new Comment()
        {
            Author = name.Trim(),
            Email = email.Trim(),
            Website = GetUrl(website),
            Ip = context.Request.UserHostAddress,
            UserAgent = context.Request.UserAgent,
            IsAdmin = context.User.Identity.IsAuthenticated,
            Content = HttpUtility.HtmlEncode(content.Trim()).Replace("\n", "<br />"),
            IsApproved = !Blog.ModerateComments,
        };

        post.Comments.Add(comment);
        Storage.Save(post);

        if (!context.User.Identity.IsAuthenticated)
            System.Threading.ThreadPool.QueueUserWorkItem((s) => SendEmail(comment, post, context.Request));

        RenderComment(context, comment);
    }

    private static void RenderComment(HttpContext context, Comment comment)
    {
        var page = (WebPage)WebPageBase.CreateInstanceFromVirtualPath("~/themes/" + Blog.Theme + "/comment.cshtml");
        page.Context = new HttpContextWrapper(context);
        page.ExecutePageHierarchy(new WebPageContext(page.Context, page: null, model: comment), context.Response.Output);
    }

    private static void SendEmail(Comment comment, Post post, HttpRequest request)
    {
        try
        {
            MailMessage mail = new MailMessage();
            mail.From = new MailAddress(comment.Email, comment.Author);
            mail.ReplyToList.Add(comment.Email);
            mail.To.Add(ConfigurationManager.AppSettings.Get("blog:email"));
            mail.Subject = "Blog comment: " + post.Title;
            mail.IsBodyHtml = true;

            string absoluteUrl = request.Url.Scheme + "://" + request.Url.Authority;
            string deleteUrl = absoluteUrl + request.RawUrl + "?postId=" + post.ID + "&commentId=" + comment.ID + "&mode=delete";
            string approveUrl = absoluteUrl + request.RawUrl + "?postId=" + post.ID + "&commentId=" + comment.ID + "&mode=approve";
            mail.Body = "<div style=\"font: 11pt/1.5 calibri, arial;\">" +
                            comment.Author + " on <a href=\"" + absoluteUrl + post.Url + "\">" + post.Title + "</a>:<br /><br />" +
                            comment.Content + "<br /><br />" +
                            (Blog.ModerateComments ? "<a href=\"" + approveUrl + "\">Approve comment</a> | " : string.Empty) +
                            "<a href=\"" + deleteUrl + "\">Delete comment</a>" +
                            "<br /><br /><hr />" +
                            "Website: " + comment.Website + "<br />" +
                            "E-mail: " + comment.Email + "<br />" +
                            "IP-address: " + comment.Ip +
                        "</div>";


            SmtpClient client = new SmtpClient();
            client.Send(mail);
        }
        catch
        { }
    }

    private static void Validate(string name, string email, string content)
    {
        bool isName = !string.IsNullOrEmpty(name);
        bool isMail = !string.IsNullOrEmpty(email) && Regex.IsMatch(email, @"^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$");
        bool isContent = !string.IsNullOrEmpty(content);

        if (!isName || !isMail || !isContent)
        {
            if (!isName)
                HttpContext.Current.Response.Status = "403 Please enter a valid name";
            else if (!isMail)
                HttpContext.Current.Response.Status = "403 Please enter a valid e-mail address";
            else if (!isContent)
                HttpContext.Current.Response.Status = "403 Please enter a valid comment";

            HttpContext.Current.Response.End();
        }
    }

    private static string GetUrl(string website)
    {
        if (!website.Contains("://"))
            website = "http://" + website;

        Uri url;
        if (Uri.TryCreate(website, UriKind.Absolute, out url))
            return url.ToString();

        return string.Empty;
    }

    private static void Delete(HttpContext context, Post post)
    {
        if (!context.User.Identity.IsAuthenticated)
            throw new HttpException(403, "No access");

        string commentId = context.Request["commentId"];
        Comment comment = post.Comments.SingleOrDefault(c => c.ID == commentId);

        if (comment != null)
        {
            post.Comments.Remove(comment);
            Storage.Save(post);
        }
        else
        {
            throw new HttpException(404, "Comment could not be found");
        }

        if (context.Request.HttpMethod == "GET")
        {
            context.Response.Redirect(post.AbsoluteUrl.ToString() + "#comments", true);
        }
    }

    private static void Approve(HttpContext context, Post post)
    {
        if (!context.User.Identity.IsAuthenticated)
            throw new HttpException(403, "No access");

        string commentId = context.Request["commentId"];
        Comment comment = post.Comments.SingleOrDefault(c => c.ID == commentId);

        if (comment != null)
        {
            comment.IsApproved = true;
            Storage.Save(post);
        }
        else
        {
            throw new HttpException(404, "Comment could not be found");
        }

        if (context.Request.HttpMethod == "GET")
        {
            context.Response.Redirect(post.AbsoluteUrl.ToString() + "#comments", true);
        }
    }

    public bool IsReusable
    {
        get { return false; }
    }
}