package com.example.petstoremobile.viewmodels;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import com.example.petstoremobile.dtos.ConversationDTO;
import com.example.petstoremobile.dtos.CustomerDTO;
import com.example.petstoremobile.dtos.MessageDTO;
import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.SendMessageRequest;
import com.example.petstoremobile.dtos.UpdateConversationStatusRequest;
import com.example.petstoremobile.models.Chat;
import com.example.petstoremobile.models.Message;
import com.example.petstoremobile.repositories.ChatRepository;
import com.example.petstoremobile.repositories.CustomerRepository;
import com.example.petstoremobile.utils.Resource;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.inject.Inject;

import dagger.hilt.android.lifecycle.HiltViewModel;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;

@HiltViewModel
public class ChatListViewModel extends ViewModel {
    private final ChatRepository chatRepository;
    private final CustomerRepository customerRepository;

    private final MutableLiveData<List<Chat>> activeChats = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<Chat>> closedChats = new MutableLiveData<>(new ArrayList<>());
    private final MutableLiveData<List<Message>> messageList = new MutableLiveData<>(new ArrayList<>());
    private final Map<Long, String> customerNames = new HashMap<>();
    private final MutableLiveData<Boolean> isLoading = new MutableLiveData<>(false);
    
    private Long lastActiveConversationId = null;

    @Inject
    public ChatListViewModel(ChatRepository chatRepository, CustomerRepository customerRepository) {
        this.chatRepository = chatRepository;
        this.customerRepository = customerRepository;
    }

    public LiveData<List<Chat>> getActiveChats() { return activeChats; }
    public LiveData<List<Chat>> getClosedChats() { return closedChats; }
    public LiveData<List<Message>> getMessageList() { return messageList; }
    public LiveData<Boolean> getIsLoading() { return isLoading; }

    public Long getLastActiveConversationId() {
        return lastActiveConversationId;
    }

    public void setLastActiveConversationId(Long conversationId) {
        this.lastActiveConversationId = conversationId;
    }

    public void loadCustomers() {
        isLoading.setValue(true);
        customerRepository.getAllCustomers(0, 100).observeForever(resource -> {
            if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) {
                for (CustomerDTO c : resource.data.getContent()) {
                    customerNames.put(c.getCustomerId(), c.getFullName());
                }
                loadConversations();
            } else if (resource != null && resource.status == Resource.Status.ERROR) {
                isLoading.setValue(false);
            }
        });
    }

    public void loadConversations() {
        isLoading.setValue(true);
        chatRepository.getAllConversations().observeForever(resource -> {
            if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) {
                List<Chat> active = new ArrayList<>();
                List<Chat> closed = new ArrayList<>();
                for (ConversationDTO dto : resource.data) {
                    String name = customerNames.getOrDefault(dto.getCustomerId(), "Customer #" + dto.getCustomerId());
                    Chat chat = new Chat(String.valueOf(dto.getId()), name, dto.getLastMessage(), dto.getCustomerId(), dto.getStaffId(), dto.getStatus());
                    if ("CLOSED".equalsIgnoreCase(dto.getStatus())) {
                        closed.add(chat);
                    } else {
                        active.add(chat);
                    }
                }
                activeChats.setValue(active);
                closedChats.setValue(closed);
                isLoading.setValue(false);
            } else if (resource != null && resource.status == Resource.Status.ERROR) {
                isLoading.setValue(false);
            }
        });
    }

    public void loadMessageHistory(Long conversationId) {
        isLoading.setValue(true);
        chatRepository.getMessages(conversationId).observeForever(resource -> {
            if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) {
                List<Message> messages = new ArrayList<>();
                for (MessageDTO dto : resource.data) {
                    messages.add(dtoToModel(dto));
                }
                messageList.setValue(messages);
                isLoading.setValue(false);
            } else if (resource != null && resource.status == Resource.Status.ERROR) {
                isLoading.setValue(false);
            }
        });
    }

    public LiveData<Resource<MessageDTO>> sendMessage(Long conversationId, String text) {
        return chatRepository.sendMessage(conversationId, new SendMessageRequest(text));
    }

    public LiveData<Resource<MessageDTO>> sendMessageWithAttachment(Long conversationId, MultipartBody.Part content, MultipartBody.Part attachment) {
        return chatRepository.sendMessageWithAttachment(conversationId, content, attachment);
    }

    public LiveData<Resource<ResponseBody>> downloadAttachment(Long messageId) {
        return chatRepository.downloadAttachment(messageId);
    }

    public LiveData<Resource<ConversationDTO>> closeConversation(Long conversationId) {
        return chatRepository.updateConversationStatus(conversationId, new UpdateConversationStatusRequest("CLOSED"));
    }

    public void addMessageLocally(MessageDTO dto) {
        List<Message> current = new ArrayList<>(messageList.getValue());
        if (dto.getId() != null) {
            for (Message m : current) {
                if (dto.getId().equals(m.getId())) return;
            }
        }
        current.add(dtoToModel(dto));
        messageList.setValue(current);
    }

    public void updateConversationLocally(ConversationDTO dto) {
        updateList(activeChats, dto);
        updateList(closedChats, dto);

        loadConversations();
    }

    private void updateList(MutableLiveData<List<Chat>> liveData, ConversationDTO dto) {
        List<Chat> current = new ArrayList<>(liveData.getValue());
        String name = customerNames.getOrDefault(dto.getCustomerId(), "Customer #" + dto.getCustomerId());
        boolean updated = false;
        for (int i = 0; i < current.size(); i++) {
            if (current.get(i).getChatId().equals(String.valueOf(dto.getId()))) {
                current.set(i, new Chat(String.valueOf(dto.getId()), name, dto.getLastMessage(), dto.getCustomerId(), dto.getStaffId(), dto.getStatus()));
                updated = true;
                break;
            }
        }
        if (updated) liveData.setValue(current);
    }

    private Message dtoToModel(MessageDTO dto) {
        Message m = new Message();
        m.setId(dto.getId());
        m.setConversationId(dto.getConversationId());
        m.setSenderId(dto.getSenderId());
        m.setContent(dto.getContent());
        m.setTimestamp(dto.getTimestamp());
        m.setIsRead(dto.getIsRead());
        m.setAttachmentUrl(dto.getAttachmentUrl());
        m.setAttachmentName(dto.getAttachmentName());
        m.setSenderRole(dto.getSenderRole());
        m.setSenderDisplayName(dto.getSenderDisplayName());
        m.setAttachmentMimeType(dto.getAttachmentMimeType());
        m.setAttachmentSizeBytes(dto.getAttachmentSizeBytes());
        return m;
    }

    public String getCustomerName(Long customerId) {
        return customerNames.getOrDefault(customerId, "Customer #" + customerId);
    }
}
