import { all, takeLatest, call, put, select } from "@redux-saga/core/effects";
import {
  attemptCreateNewChat,
  attemptFetchChats,
  attemptFetchHeaderChats,
  attemptFetchOneChat,
  attemptGetExistChat,
  attemptSendMessage,
} from "../../request/chatRequest";
import {
  CHAT_FETCH,
  CHAT_HEADER_FETCH,
  CHAT_NEW_FETCH,
  CHAT_ONE_FETCH,
  CHAT_SEND_FETCH,
  GET_EXIST_CHAT,
} from "../actions/chat/chatActionConstants";
import {
  addNewMessage,
  fetchChatsError,
  fetchChatsSuccess,
  fetchHeaderChatsError,
  fetchHeaderChatsSuccess,
  fetchOneChatError,
  fetchOneChatSuccess,
  getExistChatError,
  getExistChatSuccess,
  sendMessageError,
  sendMessageSuccess,
  setChats,
  setChatsTotal,
  setOneChat,
  startNewChatError,
  startNewChatSuccess,
} from "../actions/chat/chatActions";
import {
  setRequester,
  validateExchange,
} from "../actions/exchange/exchangeActions";
import { selectSelectedChat } from "../selectors/chatSelectors";
import { selectExchange } from "../selectors/exchangeSelector";
import { selectJwtToken, selectUserId } from "../selectors/loginSelectors";
import { sendMessage as SendMessageSocket } from "../../socket/socket";
import { KEY_PAGE, KEY_SIZE } from "../../constants/queryStringConstants";
import { setQueryStringRedux } from "../actions/queryString/queryStringActions";
import { selectQueryString } from "../selectors/queryStringSelectors";
import requesterStatus from "../../constants/requesterStatus";

function* fetchChats({ payload }) {
  try {
    const userId = yield select(selectUserId);
    let queryString;
    if (payload?.currentPage) {
      const queryObject = new URLSearchParams();
      queryObject.set(KEY_SIZE, "6");
      queryObject.set(KEY_PAGE, payload.currentPage);
      queryString = queryObject.toString();
      yield put(setQueryStringRedux(queryString));
    } else {
      queryString = yield select(selectQueryString);
    }
    const data = yield call(attemptFetchChats, {
      userId,
      queryString: queryString,
    });
    yield call(console.dir, data);
    yield put(setChats([...data.data.chats]));
    yield put(setChatsTotal(data.data.total));
    yield put(fetchChatsSuccess());
  } catch (e) {
    yield put(fetchChatsError());
    console.dir(e);
  }
}

function* fetchHeaderChats() {
  try {
    const userId = yield select(selectUserId);
    const data = yield call(attemptFetchHeaderChats, userId);
    yield put(setChats([...data.data.chats]));
    yield put(fetchHeaderChatsSuccess());
  } catch (e) {
    yield put(fetchHeaderChatsError());
    console.dir(e);
  }
}

function* fetchOneChat(payload) {
  try {
    const userId = yield select(selectUserId);
    const chatData = yield call(attemptFetchOneChat, {
      chatId: payload.payload,
      userId,
    });
    let requester = requesterStatus.NOONE;
    chatData.data.messages.forEach((item) => {
      if (requester !== requesterStatus.NOONE) return;
      if (item.isAcceptRequest) {
        if (item.user._id === userId) requester = requesterStatus.ME;
        else requester = requesterStatus.interlocutor;
      }
    });
    yield put(setRequester(requester));
    yield put(setOneChat(chatData.data));
    yield put(fetchOneChatSuccess());
  } catch (e) {
    yield put(fetchOneChatError());
    console.dir(e);
  }
}

function* sendMessage(payload) {
  try {
    const messageObject = {
      text: payload.payload.message,
    };
    const chat = yield select(selectSelectedChat);
    const exchange = yield select(selectExchange);
    const userId = yield select(selectUserId);
    yield call(attemptSendMessage, payload.payload.chatId, messageObject);
    if (chat?.offer?.user._id === userId && exchange.valid === false) {
      yield put(validateExchange(exchange._id));
    }
    yield call(fetchChats);
    yield put(sendMessageSuccess());
    if (payload.payload.handleApiResponseSuccess) {
      yield call(payload.payload.handleApiResponseSuccess);
    }
  } catch (e) {
    yield put(sendMessageError());
    console.dir(e);
  }
}
function* startNewChat(payload) {
  try {
    const userId = yield select(selectUserId);
    const newChatData = yield call(attemptCreateNewChat, {
      offerId: payload.payload.offerId,
      userId,
    });
    const queryString = yield select(selectQueryString);
    const token = yield select(selectJwtToken);
    const data = yield call(attemptFetchChats, { userId, queryString });
    yield put(setChats([...data.data.chats]));
    yield put(setChatsTotal(data.data.total));
    const newChatId = newChatData.data.chatId;
    yield put(startNewChatSuccess());
    yield call(
      SendMessageSocket,
      newChatData.data.chatId,
      userId,
      payload.payload.message,
      payload.payload.interlocutorUserId,
      token
    );
    yield put(
      addNewMessage({
        _id: newChatId,
        message: {
          user: {
            _id: userId,
          },
          text: payload.payload.message,
          _created: new Date().toISOString(),
        },
      })
    );
    if (payload.payload.handleMessageSendSuccess) {
      yield call(payload.payload.handleMessageSendSuccess, newChatId);
    }
  } catch (e) {
    yield put(startNewChatError());
    console.dir(e);
  }
}

function* getExistChat(payload) {
  try {
    const data = yield call(attemptGetExistChat, {
      userId: payload.payload.userId,
      offerId: payload.payload.offerId,
    });
    console.log(data);
    yield put(getExistChatSuccess());

    if (payload.payload.handleApiResponseSuccess) {
      yield call(payload.payload.handleApiResponseSuccess, data.data);
    }
  } catch (error) {
    yield put(getExistChatError());
    console.log(error);
  }
}

export default function* chatSaga() {
  yield all([
    takeLatest(CHAT_FETCH, fetchChats),
    takeLatest(CHAT_ONE_FETCH, fetchOneChat),
    takeLatest(CHAT_HEADER_FETCH, fetchHeaderChats),
    takeLatest(CHAT_SEND_FETCH, sendMessage),
    takeLatest(CHAT_NEW_FETCH, startNewChat),
    takeLatest(GET_EXIST_CHAT, getExistChat),
  ]);
}
