import type { AxiosRequestConfig, AxiosInstance, AxiosResponse } from 'axios';
import axios from 'axios'

// import LoginModule from '../Modules/Auth/LoginStore'
import { toolsext } from '@src/store/Modules/toolsext'
import { serv_constants } from '@src/store/Modules/serv_constants'
import { useGlobalStore } from '@store/globalStore'
import { useUserStore } from '@store/UserStore'
import { tools } from '@src/store/Modules/tools'
import * as Types from './ApiTypes'

import type { Observable } from 'rxjs';
import { from } from 'rxjs';
import { mergeMap, toArray } from 'rxjs/operators';

export let API_URL = ''
export const axiosInstance: AxiosInstance = axios.create({
  baseURL: API_URL,
  headers: {
    Accept: 'application/json',
  },
})


axiosInstance.interceptors.response.use(

  (response) => {
    if (import.meta.env.VITE_DEBUG === '1') console.log(response)
    return response
  },
  (error) => {
    const globalStore = useGlobalStore()
    // console.log('error', error)
    if (error.response) {
      if (import.meta.env.VITE_DEBUG === '1') console.log('Status = ', error.response.status)
      console.log('Request Error: ', error.response)
      if (error.response.status !== 0) {
        globalStore.setStateConnection('online')
      } else {
        globalStore.setStateConnection('offline')
      }
    } else {
      globalStore.setStateConnection('offline')
    }
    return Promise.reject(error)
  },
)

export const addAuthHeaders = () => {
  // axiosInstance.defaults.headers.Authorization = `Bearer ${LoginModule.userInfos.userToken}`
}

//export const removeAuthHeaders = () => {
//  delete axiosInstance.defaults.headers.Authorization
//}

async function generateStream(path: string, payload: any, config?: RequestInit, options?: any): Promise<AsyncIterable<any>> {
  const userStore = useUserStore()

  const mieiparam: any = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-auth': userStore.x_auth_token,
      'x-refrtok': userStore.refreshToken,
    },
    body: JSON.stringify(payload),
    signal: options?.signal,
    ...config
  }

  console.log('marams: ', mieiparam)

  const response = await fetch(
    path,
    mieiparam,
  );
  console.log('USCITA DA FETCH... !!!!!')
  if (response.status !== 200) throw new Error(response.status.toString());
  return getIterableStream(response);
}

function getIterableStream(stream: NodeJS.ReadableStream): AsyncIterable<any> {
  return {
    [Symbol.asyncIterator](): AsyncIterator<any> {
      let buffer = '';
      return {
        async next(): Promise<IteratorResult<any>> {
          while (true) {
            const chunk = await new Promise<string>((resolve, reject) => {
              stream.once('data', (data: Buffer) => resolve(data.toString()));
              stream.once('error', (err) => reject(err));
              stream.once('end', () => resolve(''));
            });
            buffer += chunk;
            if (buffer.includes('\n\n')) {
              const event = buffer.slice(0, buffer.indexOf('\n\n'));
              buffer = buffer.slice(buffer.indexOf('\n\n') + 2);
              try {
                return { value: JSON.parse(event.slice('data: '.length)), done: false };
              } catch (error) {
                console.error('Error parsing event data:', error);
              }
            } else if (chunk === '') {
              return { value: undefined, done: true };
            }
          }
        },
      };
    },
  };
}

// Funzione helper per inviare la richiesta HTTP
async function Request(type, path, payload, responsedata = {}, options = {}) {
  const userStore = useUserStore();
  const globalStore = useGlobalStore();
  const baseURL = globalStore.getServerHost();

  try {
    if (tools.isDebug()) console.log('Axios Request', path, type, tools.notshowPwd(payload));

    const isFormData = type === 'postFormData';
    const config = {
      baseURL,
      headers: {
        'Content-Type': isFormData ? 'multipart/form-data' : 'application/json',
        'x-auth': userStore.x_auth_token,
        'x-refrtok': userStore.refreshToken,
      },
      ...responsedata,
    };

    if (options?.stream) config.responseType = 'stream';

    let response;
    const method = type.toLowerCase();

    // Gestione dinamica del metodo HTTP
    if (['post', 'put', 'patch'].includes(method)) {
      if (options?.stream) {
        // Gestione stream (riconosciuta come promise)
        const stream = await generateStream(path, payload, config, options);
        return new Promise((resolve, reject) => {
          from(stream)
            .pipe(
              mergeMap(event => from([event])),
              toArray()
            )
            .subscribe(
              (data) => {
                console.log('Received data:', data);
                resolve({
                  data,
                  status: response.status,
                  statusText: response.statusText,
                  headers: response.headers,
                  config: response.config,
                });
              },
              (error) => {
                console.error('Stream error:', error);
                reject(error);
              },
              () => console.log('Stream completed')
            );
        });
      } else {
        response = await axiosInstance[method](path, payload, config);
      }
    } else if (['get', 'delete'].includes(method)) {
      response = await axiosInstance[method](path, {
        baseURL,
        params: payload,
        headers: {
          'Content-Type': 'application/json',
          'x-auth': userStore.x_auth_token,
          'x-refrtok': userStore.refreshToken,
        },
        ...responsedata,
      });
    } else if (type === 'postFormData') {
      response = await axiosInstance.post(path, payload, config);
    } else {
      throw new Error(`Unsupported request type: ${type}`);
    }

    // Gestione aggiornamento token se necessario
    const setAuthToken = (path === '/updatepwd' || path === '/users/login');
    if (response && response.status === 200 && (setAuthToken || path === '/users/login')) {
      const x_auth_token = String(response.headers['x-auth'] || '');
      const refreshToken = String(response.headers['x-refrtok'] || '');
      if (!x_auth_token) {
        userStore.setServerCode(toolsext.ERR_AUTHENTICATION);
      }
      if (setAuthToken) {
        userStore.UpdatePwd(x_auth_token, refreshToken);
        localStorage.setItem(toolsext.localStorage.token, x_auth_token);
        localStorage.setItem(toolsext.localStorage.refreshToken, refreshToken);
      }
      userStore.setAuth(x_auth_token, refreshToken);
      localStorage.setItem(toolsext.localStorage.token, x_auth_token);
      localStorage.setItem(toolsext.localStorage.refreshToken, refreshToken);
    }

    globalStore.setStateConnection('online');
    userStore.setServerCode(tools.OK);
    return new Types.AxiosSuccess(response.data, response.status);
  } catch (error) {
    // Aggiornamento asincrono dello stato di connessione (setTimeout per dare tempo a eventuali animazioni)
    setTimeout(() => {
      if (['get'].includes(type.toLowerCase())) {
        globalStore.connData.downloading_server = (globalStore.connData.downloading_server === 1) ? -1 : globalStore.connData.downloading_server;
      } else {
        globalStore.connData.uploading_server = (globalStore.connData.uploading_server === 1) ? -1 : globalStore.connData.uploading_server;
        globalStore.connData.downloading_server = (globalStore.connData.downloading_server === 1) ? -1 : globalStore.connData.downloading_server;
      }
    }, 1000);

    if (import.meta.env.DEV) {
      console.log('ERROR using', path);
      console.log('error.response=', error.response);
    }
    let mycode = 0;
    if (error.response) {
      const code = error.response.data?.code || 0;
      mycode = code;
      userStore.setServerCode(mycode);
      return Promise.reject(new Types.AxiosError(error.response.status, error.response.data, code));
    }
    return Promise.reject(new Types.AxiosError(0, null, mycode, error));
  }
}

export default Request
