
using song_of_the_day;

public class LinkPreviewAttachment
{
    public required string Url { get; set; }
    public required string Title { get; set; }
    public required string Description { get; set; }
    public required string Base64Image { get; set; }
}

public class SignalIntegration
{
    private readonly ILogger<SignalIntegration> logger;

    public SignalIntegration(ILogger<SignalIntegration> logger)
    {

        var uri = AppConfiguration.Instance.SignalAPIEndpointUri;
        var port = int.Parse(AppConfiguration.Instance.SignalAPIEndpointPort);
        var phoneNumber = AppConfiguration.Instance.HostPhoneNumber;
        this.logger = logger;

        var http = new HttpClient()
        {
            BaseAddress = new Uri(uri + ":" + port),
            Timeout = TimeSpan.FromSeconds(180),
        };
        apiClient = new swaggerClient(http);
        apiClient.BaseUrl = "";
        this.phoneNumber = phoneNumber;
    }

    private swaggerClient apiClient;

    private string phoneNumber;

    public async Task GetMessagesAsync()
    {
        var messages = await apiClient.ReceiveAsync(this.phoneNumber, "120", "true", "true", "50", "false");
        logger.LogInformation($"Received {messages.Count} Signal messages.");
    }

    public async Task ListGroupsAsync()
    {
        logger.LogDebug("Listing all groups for phone number: {PhoneNumber}", this.phoneNumber);

        try
        {
            ICollection<song_of_the_day.GroupEntry> groupEntries = await apiClient.GroupsAllAsync(this.phoneNumber);
            foreach (var group in groupEntries)
            {
                logger.LogDebug($"  {group.Name} {group.Id}");
            }
        }
        catch (Exception ex)
        {
            logger.LogError("Exception (ListGroupsAsync): " + ex.Message);
        }
    }

    public async Task SendMessageToGroupAsync(string message)
    {
        try
        {
            SendMessageV2 data = new SendMessageV2();
            data.Recipients = new List<string>();
            data.Recipients.Add(AppConfiguration.Instance.SignalGroupId);
            data.Message = (AppConfiguration.Instance.UseBotTag ? "**[Proggy]**\n" : "") + message;
            data.Text_mode = SendMessageV2Text_mode.Styled;
            data.Number = AppConfiguration.Instance.HostPhoneNumber;
            var response = await apiClient.Send2Async(data);
        }
        catch (Exception ex)
        {
            logger.LogError("Exception (SendMessageToGroupAsync): " + ex.Message);
        }
    }

    public async Task SendMessageToGroupAsync(string message, LinkPreviewAttachment previewData)
    {
        try
        {
            SendMessageV2 data = new SendMessageV2();
            data.Recipients = new List<string>();
            data.Recipients.Add(AppConfiguration.Instance.SignalGroupId);
            data.Message = (AppConfiguration.Instance.UseBotTag ? "**[Proggy]**\n" : "") + message;
            data.Text_mode = SendMessageV2Text_mode.Styled;
            data.Number = AppConfiguration.Instance.HostPhoneNumber;
            data.Link_preview = new LinkPreviewType();
            data.Link_preview.Url = previewData.Url;
            data.Link_preview.Title = previewData.Title;
            data.Link_preview.Description = previewData.Description;
            data.Link_preview.Base64_thumbnail = previewData.Base64Image;
            var response = await apiClient.Send2Async(data);
        }
        catch (Exception ex)
        {
            logger.LogError("Exception (SendMessageToGroupAsync): " + ex.Message);
        }
    }

    public async Task SendMessageToUserAsync(string message, string userId)
    {
        try
        {
            SendMessageV2 data = new SendMessageV2();
            data.Recipients = new List<string>();
            data.Recipients.Add(userId);
            data.Message = (AppConfiguration.Instance.UseBotTag ? "**[Proggy]**\n" : "") + message;
            data.Text_mode = SendMessageV2Text_mode.Styled;
            data.Number = AppConfiguration.Instance.HostPhoneNumber;
            var response = await apiClient.Send2Async(data);
        }
        catch (Exception ex)
        {
            logger.LogError("Exception (SendMessageToUserAsync): " + ex.Message);
        }
    }

    public async Task SendMessageToUserAsync(string message, LinkPreviewAttachment previewData, string userId)
    {
        try
        {
            SendMessageV2 data = new SendMessageV2();
            data.Recipients = new List<string>();
            data.Recipients.Add(userId);
            data.Message = (AppConfiguration.Instance.UseBotTag ? "**[Proggy]**\n" : "") + message;
            data.Text_mode = SendMessageV2Text_mode.Styled;
            data.Number = AppConfiguration.Instance.HostPhoneNumber;
            data.Link_preview = new LinkPreviewType();
            data.Link_preview.Url = previewData.Url;
            data.Link_preview.Title = previewData.Title;
            data.Link_preview.Description = previewData.Description;
            data.Link_preview.Base64_thumbnail = previewData.Base64Image;
            var response = await apiClient.Send2Async(data);
        }
        catch (Exception ex)
        {
            logger.LogError("Exception (SendMessageToUserAsync): " + ex.Message);
        }
    }

    public async Task IntroduceUserAsync(User user)
    {
        if (user == null || user.SignalMemberId == null)
        {
            logger.LogWarning("Attempt to introduce unknown user was aborted.");
            return;
        }
        await this.SendMessageToUserAsync("Hi, my name is Proggy and I am your friendly neighborhood *Song of the Day* bot!", user.SignalMemberId);
        await this.SendMessageToUserAsync("You are receiving this message because you have been invited to a *Song of the Day* community group.", user.SignalMemberId);
        await this.SendMessageToUserAsync("In that community group I will pick a person at random every now and then and encourage them to share a song with the rest of the community.", user.SignalMemberId);
        if (AppConfiguration.Instance.UseBotTag)
        {
            await this.SendMessageToUserAsync("You can always see which messages are sent by me rather than the community host by the **[Proggy]** tag at the beginning of the message", user.SignalMemberId);
        }
        await this.SendMessageToUserAsync($"You can find more details about your community at {AppConfiguration.Instance.WebUIBaseURL}.", user.SignalMemberId);
        await this.SendMessageToUserAsync($"""You can navigate to {AppConfiguration.Instance.WebUIBaseURL + (AppConfiguration.Instance.WebUIBaseURL.EndsWith("/") ? "" : "/")}User/{user.UserId} to set your preferred display name for me to use.""", user.SignalMemberId);
        await this.SendMessageToUserAsync($"Now have fun and enjoy being a part of this community!", user.SignalMemberId);
    }

    public async Task<ICollection<string>> GetMemberListAsync()
    {
        try
        {
            var response = await apiClient.Groups2Async(AppConfiguration.Instance.HostPhoneNumber, AppConfiguration.Instance.SignalGroupId);
            return response.Members;
        }
        catch (Exception ex)
        {
            logger.LogError("Exception (GetMemberListAsync): " + ex.Message);
        }
        return new List<string>();
    }

    public async Task<ListContactsResponse> GetContactAsync(string memberId)
    {
        try
        {
            var allIdentities = await apiClient.ContactsAllAsync(AppConfiguration.Instance.HostPhoneNumber);
            var identityCandidates = allIdentities.Where(u => u.Number == memberId || u.Uuid == memberId);
            var identity = identityCandidates.SingleOrDefault();
            if (identity == null)
            {
                throw new Exception($"Could not determine identity for memberId '{memberId}'!");
            }
            return identity;
        }
        catch (Exception ex)
        {
            logger.LogError("Exception (GetContactAsync): " + ex.Message);
            return new ListContactsResponse();
        }
    }
}