using System.Net.Mime;
using System.Text.RegularExpressions;
using System.Xml;
using FitConnect.Models;
using Newtonsoft.Json;

namespace FitConnect;

public class SubmissionBuilder : ISubmissionWithDestination,
    ISubmissionWithServiceType, ISubmissionWithData {
    protected readonly SendableSubmission _submissionToSend;


    private protected SubmissionBuilder(string destinationId) {
        _submissionToSend = new SendableSubmission(destinationId);
    }

    public ISubmissionWithData WithAttachments(List<Attachment> attachments) {
        return WithAttachments(attachments.ToArray());
    }

    public ISubmissionWithData WithAttachments(string fileName, string description, string mimeType,
        FileStream fileStream) {
        byte[]? buffer;
        using (fileStream) {
            buffer = new byte[fileStream.Length];
            fileStream.Read(buffer, 0, (int)fileStream.Length);
        }

        var attachment = new Attachment(fileName, description, mimeType, buffer);

        return WithAttachments(attachment);
    }

    public ISubmissionWithData WithAttachments(params Attachment[] attachments) {
        _submissionToSend.Attachments ??= new Attachment[] { };

        foreach (var attachment in attachments) {
            _submissionToSend.Attachments =
                _submissionToSend.Attachments.Append(attachment).ToArray();
        }

        return this;
    }

    public SendableSubmission Build() {
        return _submissionToSend;
    }

    public ISubmissionWithServiceType WithServiceType(string serviceName, string leikaKey) {
        if (string.IsNullOrWhiteSpace(leikaKey) || !Regex.IsMatch(leikaKey,
                FitConnectClient.LeikaKeyPattern))
            throw new ArgumentException("Invalid leika key");

        _submissionToSend.ServiceName = serviceName;
        _submissionToSend.LeikaKey = leikaKey;
        return this;
    }

    public ISubmissionWithData WithXmlData(string data) {
        try {
            var doc = new XmlDocument();
            doc.LoadXml(data);
        }
        catch (Exception e) {
            throw new ArgumentException("The data must be valid XML string", e);
        }

        _submissionToSend.Data = data;
        _submissionToSend.DataMimeType = MediaTypeNames.Application.Xml;
        return this;
    }


    public ISubmissionWithData WithJsonData(string data) {
        try {
            JsonConvert.DeserializeObject(data);
        }
        catch (Exception e) {
            throw new ArgumentException("The data must be valid JSON string", e);
        }

        _submissionToSend.Data = data;
        _submissionToSend.DataMimeType = MediaTypeNames.Application.Json;
        return this;
    }

    public static ISubmissionWithDestination WithDestination(string destinationId) {
        if (!Regex.IsMatch(destinationId,
                FitConnectClient.GuidPattern))
            throw new ArgumentException("The destination must be a valid GUID");

        var result = new SubmissionBuilder(destinationId);
        return result;
    }
}

public interface ISubmissionWithDestination {
    ISubmissionWithServiceType WithServiceType(string serviceName, string leikaKey);
}

public interface ISubmissionWithServiceType {
    ISubmissionWithData WithJsonData(string data);
    ISubmissionWithData WithXmlData(string data);
}

public interface ISubmissionWithData {
    ISubmissionWithData WithAttachments(params Attachment[] attachments);
    ISubmissionWithData WithAttachments(List<Attachment> attachments);

    ISubmissionWithData WithAttachments(string fileName, string description, string mimeType,
        FileStream content);


    SendableSubmission Build();
}