/*
 Copyright (C) 2020 - 2025 3NSoft Inc.

 This program is free software: you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation, either version 3 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { computed, ref, shallowRef } from 'vue';
import { storeToRefs } from 'pinia';
import size from 'lodash/size';
import { getDeliveryErrors } from '@v1nt1248/3nclient-lib/utils';
import { makeServiceCaller } from '@shared/ipc/ipc-service-caller';
import { appDeliverySrv } from '@main/services/services-provider';
import { UISettings } from '@main/helpers/ui-settings';
import type { AppDeliveryService } from '~/index';
import { makeIncomingMessageHandler } from '@main/ctrl-funcs/handle-incoming-message';
import { handleUpdateMessageStatus } from '@main/ctrl-funcs/system-message-handlers/handle-update-message-status';
import { useChatsStore } from '@main/store/chats';
import { useAppStore } from '@main/store/app';
import { useContactsStore } from '@main/store/contacts';

export type AppViewInstance = ReturnType<typeof useAppView>;

export function useAppView() {

  const appStore = useAppStore();
  const contactsStore = useContactsStore();
  const chatsStore = useChatsStore();

  const { appVersion, user: me, connectivityStatus } = storeToRefs(appStore);
  const {
    fetchInitData,
    fetchConnectivityStatus,
    setLang,
    setColorTheme,
    setAppWindowSize,
  } = appStore;

  const { fetchContactList } = contactsStore;

  const { fetchChatList } = chatsStore;

  const appElement = shallowRef<HTMLElement>();

  const connectivityStatusText = computed(() =>
    connectivityStatus.value === 'online' ? 'app.status.connected.online' : 'app.status.connected.offline',
  );
  const connectivityTimerId = ref<ReturnType<typeof setInterval>>();

  const resizeObserver = new ResizeObserver((entries) => {
    for (const entry of entries) {
      const { contentRect, target } = entry;
      const { className } = target;
      const { width, height } = contentRect;
      if (className === 'app') {
        setAppWindowSize({ width, height });
      }
    }
  });

  async function appExit() {
    w3n.closeSelf!();
  }

  async function doBeforeMount() {
    try {
      await fetchContactList();
      await fetchInitData();
      await fetchConnectivityStatus();

      connectivityTimerId.value = setInterval(fetchConnectivityStatus, 60000);

      const config = await UISettings.makeResourceReader();
      config.watchConfig({
        next: appConfig => {
          const { lang, colorTheme } = appConfig;
          setLang(lang);
          setColorTheme(colorTheme);
        },
      });

      await fetchChatList();

      const deliverySrvConnection = await w3n.rpc!.thisApp!('ChatDeliveryService');
      const deliverSrv = makeServiceCaller(
        deliverySrvConnection,
        [],
        ['watchIncomingMessages', 'watchOutgoingMessages'],
      ) as AppDeliveryService;

      deliverSrv.watchIncomingMessages({
        next: makeIncomingMessageHandler(chatsStore, contactsStore, me.value),
        error: (e) => console.error(e),
        complete: () => deliverySrvConnection.close(),
      });

      deliverSrv.watchOutgoingMessages({
        next: (val) => {
          const { id, progress } = val;
          const { allDone, recipients } = progress;
          if (allDone) {
            appDeliverySrv.removeMessageFromDeliveryList([id]);
            const errors = getDeliveryErrors(progress);
            const { localMeta = {} } = progress;
            const { path } = localMeta;

            if (!path.includes('system')) {
              // TODO it's necessary to change when we will add new delivery status (not only 'sent' or 'error')
              const status = size(errors) === 0 || size(recipients) > size(errors) ? 'sent' : 'error';

              handleUpdateMessageStatus(chatsStore, { msgId: id, value: status });
            }
          }
        },
        error: (e) => console.error(e),
        complete: () => deliverySrvConnection.close(),
      });
    } catch (e) {
      console.error('MOUNT ERROR: ', e);
      throw e;
    }
  }

  function doWhenMounted() {
    if (appElement.value) {
      const { width, height } = appElement.value.getBoundingClientRect();
      setAppWindowSize({ width, height });
      resizeObserver.observe(appElement.value);
    }
  }

  function doBeforeUnmount() {
    connectivityTimerId.value && clearInterval(connectivityTimerId.value!);
  }

  return {
    appExit,
    appElement,
    appVersion,
    connectivityStatusText,
    doBeforeMount,
    doWhenMounted,
    doBeforeUnmount,
    me,
  };
}