<script>
import {authenticatedRequest} from "@/components/session/authenticatedRequest.vue";
import {ref} from "vue";
import {parseError} from "@/components/request/HandleGlobalError.vue";
import {SuperUserObject} from "@/components/session/token/superUserObject.vue";
import {AdminUserObject} from "@/components/session/token/AdminUserObject.vue";
import {EditFieldForm} from "@/components/session/token/SessionUser/EditFieldForm.vue";
import {reCAPTCHA} from "@/components/session/token/SessionUser/reCAPTCHA/reCAPTCHA.vue";
import {Categories} from "@/components/session/token/SessionUser/Objects/Categories.vue";
import {Products} from "@/components/session/token/SessionUser/Objects/Products.vue";
import {ProductOptions} from "@/components/session/token/SessionUser/Objects/ProductOptions.vue";
import {Departments} from "@/components/session/token/SessionUser/Objects/Departments.vue";
import {DepartmentCategories} from "@/components/session/token/SessionUser/Objects/DepartmentCategories.vue";
import {EconomicDepartments} from "@/components/session/token/SessionUser/Objects/economicDepartments.vue";
import {EconomicProducts} from "@/components/session/token/SessionUser/Objects/economicProducts.vue";
import {Roles} from "@/components/session/token/SessionUser/Objects/Roles.vue";
import {Permissions} from "@/components/session/token/SessionUser/Objects/Permissions.vue";
import {CollectedOrderInvoices} from "@/components/session/token/SessionUser/Objects/CollectedOrderInvoices.vue";
import {DepartmentDailyReports} from "@/components/session/token/SessionUser/Objects/DepartmentDailyReports.vue";
import {Notifications} from "@/components/session/token/SessionUser/Objects/Notifications.vue";
import {Bookings} from "@/components/session/token/SessionUser/Objects/Bookings.vue";
import {Orders} from "@/components/session/token/SessionUser/Objects/Orders.vue";
import {Forms} from "@/components/session/token/SessionUser/Objects/Forms.vue";
import {Branding} from "@/components/session/token/SessionUser/Objects/Brandings.vue";
import {Vehicles} from "@/components/session/token/SessionUser/Objects/Vehicles.vue";
import {DepartmentNotificationSms} from "@/components/session/token/SessionUser/Objects/DepartmentNotificationSms.vue";
import {DepartmentTimeBookingsOpeningHours} from "@/components/session/token/SessionUser/Objects/DepartmentTimeBookingsOpeningHours.vue";
import {DepartmentTimeBookingsTypes} from "@/components/session/token/SessionUser/Objects/DepartmentTimeBookingsTypes.vue";
import {DepartmentTimeBookingsEntries} from "@/components/session/token/SessionUser/Objects/DepartmentTimeBookingsEntries.vue";
import {DepartmentVariables} from "@/components/session/token/SessionUser/Objects/DepartmentVariables.vue";
import {XLVaskVehicleTypes} from "@/components/session/token/SessionUser/Objects/XLVaskVehicleTypes.vue";
import {ObjectsGlobal} from "@/components/session/token/SessionUser/Objects/ObjectsGlobal.vue";
import {useRouter} from "vue-router";
import Swal from "sweetalert2";

/**
 * Initiate the user session on app start
 * @returns {Promise<void>}
 */
export const initiateOnAppStart = async () => {
  // Check if the user has a token stored in local storage
  if (localStorage.getItem("token") !== null) {
    // Set the token and authenticated status
    SessionUser.token.value = localStorage.getItem("token");
    SessionUser.authenticated.value = true;
    // Fetch the user's session data
    await getSessionData();
  }
};

/**
 * Authenticate the user
 * @param {string} customer_number
 * @param {string} password
 * @returns {Promise<void>}
 */
export const authenticateUser = async (customer_number, password) => {
  return await authenticatedRequest("/auth/login", "POST", {
    customer_number,
    password,
  })
      .then((response) => {
        SessionUser.token.value = response.data.token;
        SessionUser.authenticated.value = true;
        localStorage.setItem("token", response.data.token);
        // Reload the window to make sure the user's session is initiated
        window.location.reload();
      })
      .catch((error) => {
        parseError(error, 'auth');
        console.error(error);
      });
};

/**
 * Get the user's session data
 * @returns {Promise<void>}
 */
export const getSessionData = async () => {
  return await authenticatedRequest("/auth/session", "GET")
      .then((response) => {
        SessionUser.user.id.value = response.data.data.id;
        SessionUser.user.customer_number.value = response.data.data.customer_number;
        SessionUser.user.group_id.value = response.data.data.group_id;
        SessionUser.user.email.value = response.data.data.email;
        SessionUser.user.phone.phone.value = response.data.data.phone.phone;
        SessionUser.user.phone.country_code.value = response.data.data.phone.country_code;
        SessionUser.user.created_at.value = response.data.data.created_at;
        SessionUser.user.updated_at.value = response.data.data.updated_at;
        SessionUser.user.display_name.value = response.data.data.display_name;
        // Set the last cached time to now, this is used to determine if the user's data is outdated
        SessionUser.user.cached_at.value = new Date();
        SessionUser.permissions.value = response.data.data.permissions;
        // E-conomic data is only fetched if the array isn't empty
        if (response.data.data.economic_customer.length > 0) {
          SessionUser.economicData.customerNumber.value = response.data.data.economic_customer.customerNumber;
          SessionUser.economicData.name.value = response.data.data.economic_customer.name;
          // Set the display name to the e-conomic name if it's empty
          if (SessionUser.user.display_name.value === null || SessionUser.user.display_name.value === 'Unnamed') {
            SessionUser.user.display_name.value = response.data.data.economic_customer.name;
          }
          SessionUser.economicData.address.value = response.data.data.economic_customer.address;
          SessionUser.economicData.zip.value = response.data.data.economic_customer.zip;
          SessionUser.economicData.city.value = response.data.data.economic_customer.city;
          SessionUser.economicData.mobilePhone.value = response.data.data.economic_customer.mobilePhone;
          SessionUser.economicData.email.value = response.data.data.economic_customer.email;
          SessionUser.economicData.cvr.value = response.data.data.economic_customer.corporateIdentificationNumber;
          SessionUser.economicData.currency.value = response.data.data.economic_customer.currency;
          SessionUser.economicData.country.value = response.data.data.economic_customer.country;
          SessionUser.economicData.cached_at.value = new Date();
        }
        SessionUser.initiated.value = true;
      })
      .catch((error) => {
        parseError(error, 'auth');
        console.error(error);
      });
};

/**
 * Destroy the user's session
 * @returns {Promise<void>}
 */
export const destroySession = async () => {
  return await authenticatedRequest("/auth/logout", "GET")
      .then(() => {
        SessionUser.forceRefresh();
        localStorage.removeItem("token");
      })
      .catch((error) => {
        parseError(error, 'auth');
        console.error(error);
      });
};

/**
 * Force sign out the user
 */
export const forceClearSession = () => {
  localStorage.removeItem("token");
  SessionUser.forceRefresh();
};

/**
 * Define the user session variables
 */
export const SessionUser = {
  user: {
    id: ref(null),
    customer_number: ref(null),
    display_name: ref(null),
    group_id: ref(null),
    email: ref(null),
    phone: {
      phone: ref(null),
      country_code: ref(null),
    },
    created_at: ref(null),
    updated_at: ref(null),
    cached_at: ref(null),
  },
  /** The user's permissions */
  permissions: ref([]),
  hasPermission: (permission) => {
    let hasPermission = (SessionUser.permissions.value.includes(permission) || SessionUser.permissions.value.includes('superuser'));
    console.log('Checking permission: ' + permission + ' - ' + hasPermission);
    return hasPermission;
  },
  /** Can access shortcuts */
  canAccessAdmin: () => {
    return SessionUser.hasPermission('admin') || SessionUser.hasPermission('superuser');
  },
  canAccessSuperUser: () => {
    return SessionUser.hasPermission('superuser');
  },
  canAccessUser: () => {
    return SessionUser.hasPermission('user');
  },
  canAccessDepartment: (id = 0) => {
    return (SessionUser.hasPermission('department_access_' + parseInt(id)) || SessionUser.canAccessSuperUser());
  },
  canAccessDeveloper: () => {
    // If the url is localhost, we can assume that the user is a developer
    return window.location.hostname === "localhost";
  },
  /** Shortcuts for the user's group */
  superUser: SuperUserObject,
  adminUser: AdminUserObject,

  /** Objects */
  objects: {
    categories: Categories,
    products: Products,
    product_options: ProductOptions,
    departments: Departments,
    department_categories: DepartmentCategories,
    economic_departments: EconomicDepartments,
    economic_products: EconomicProducts,
    roles: Roles,
    permissions: Permissions,
    collectedOrderInvoices: CollectedOrderInvoices,
    department_daily_reports: DepartmentDailyReports,
    notifications: Notifications,
    orders: Orders,
    forms: Forms,
    bookings: Bookings,
    Branding: Branding,
    vehicles: Vehicles,
    department_notification_sms: DepartmentNotificationSms,
    department_time_bookings_opening_hours: DepartmentTimeBookingsOpeningHours,
    department_time_bookings_types: DepartmentTimeBookingsTypes,
    department_time_bookings_entries: DepartmentTimeBookingsEntries,
    department_variables: DepartmentVariables,
    xlvask_vehicle_types: XLVaskVehicleTypes,
    global: ObjectsGlobal,
  },
  /** The user's token and authentication status */
  token: ref(null),
  authenticated: ref(false),
  /** The user's e-conomic data */
  economicData: {
    customerNumber: ref(null),
    name: ref(null),
    address: ref(null),
    zip: ref(null),
    city: ref(null),
    mobilePhone: ref(null),
    email: ref(null),
    cvr: ref(null),
    currency: ref(null),
    country: ref(null),
    cached_at: ref(null),
  },
  /** Check if the user's data is outdated (Older than 24 hours) */
  isDataOutdated: () => {
    return new Date() - SessionUser.user.cached_at.value > 1000 * 60 * 60 * 24;
  },
  /** Check if the user's e-conomic data is outdated (Older than 24 hours) */
  isEconomicDataOutdated: () => {
    return new Date() - SessionUser.economicData.cached_at.value > 1000 * 60 * 60 * 24;
  },
  /** Check if the user has e-conomic data */
  hasEconomicData: () => {
    return SessionUser.economicData.customerNumber.value !== null;
  },
  /** Is the object fully initiated */
  initiated: ref(false),
  isInitiated: () => {
    return SessionUser.initiated.value;
  },
  /**
   * Check if the user has a superuser token stored (This is used when the superuser is impersonating a user)
   * @returns {boolean}
   */
  hasSuperUserToken: () => {
    return localStorage.getItem("superuser_token") !== null;
  },
  /**
   * Set the user's token
   * @param {string} token
   */
  setToken: (token) => {
    SessionUser.token.value = token;
    localStorage.setItem("token", token);
    // Reload the window to make sure the user's session is initiated
    window.location.reload();
  },
  /** Reset the user's session data (Cache) */
  forceRefresh: () => {
    SessionUser.user.id.value = null;
    SessionUser.user.customer_number.value = null;
    SessionUser.user.display_name.value = null;
    SessionUser.user.group_id.value = null;
    SessionUser.user.email.value = null;
    SessionUser.user.phone.phone.value = null;
    SessionUser.user.phone.country_code.value = null;
    SessionUser.user.created_at.value = null;
    SessionUser.user.updated_at.value = null;
    SessionUser.user.cached_at.value = null;
    SessionUser.permissions.value = [];
    SessionUser.authenticated.value = false;
    SessionUser.economicData.customerNumber.value = null;
    SessionUser.economicData.name.value = null;
    SessionUser.economicData.address.value = null;
    SessionUser.economicData.zip.value = null;
    SessionUser.economicData.city.value = null;
    SessionUser.economicData.mobilePhone.value = null;
    SessionUser.economicData.email.value = null;
    SessionUser.economicData.cvr.value = null;
    SessionUser.economicData.currency.value = null;
    SessionUser.economicData.country.value = null;
    SessionUser.economicData.cached_at.value = null;
    getSessionData();
  },
  auth: {
    /** Authenticate the user */
    authenticate: authenticateUser,
    /** Logout the user */
    logout: destroySession,
    /** Force clear the user's session WARNING: This will not destroy the user's token */
    forceClearSession: forceClearSession,
    /** reCAPTCHA */
    reCAPTCHA: reCAPTCHA,
    },
  functions: {
    /** Check if the user has a token */
    hasToken: () => {
      return SessionUser.token.value !== null;
    },
    ucFirst: (str) => {
      return str.charAt(0).toUpperCase() + str.slice(1);
    },
    /** Show confirm logout dialog */
    showConfirmLogoutDialog: () => {
      Swal.fire(
          {
            title: 'Er du sikker?',
            text: "Du vil blive logget ud af systemet",
            icon: 'warning',
            showCancelButton: true,
            confirmButtonText: 'Ja, log mig ud',
            cancelButtonText: 'Annuller'
          }
      ).then((result) => {
        if (result.isConfirmed) {
          SessionUser.auth.logout().then(() => {
              SessionUser.auth.forceClearSession();
              SessionUser.functions.redirectTo.pages.login();
          });
        }
      });
    },
    /** Get the department id from the url */
    getDepartmentIdFromUrl: () => {
      // Check if the department id is in the route
      const router = useRouter();
      return parseInt(router.currentRoute.value.params.departmentId) > 0 ? parseInt(router.currentRoute.value.params.departmentId) : undefined;
    },
    /** Get the department ids the user has access to */
    getAccessibleDepartments: () => {
      return SessionUser.permissions.value.filter(permission => permission.includes('department_access_')).map(permission => parseInt(permission.split('_').pop()));
    },
    currency: {
      toLocal: (value) => {
        return new Intl.NumberFormat('da-DK', {style: 'currency', currency: 'DKK'}).format(value);
      },
    },
    date: {
      // Format to 2023-01-01 12:00:00
      format: (date) => {
        return new Date(date).toISOString().slice(0, 19).replace('T', ' ');
      },
      toWords: (date) => {
        const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
        return new Date(date).toLocaleDateString('da-DK', options);
      },
      toLocal: (date) => {
        return new Date(date).toLocaleString('da-DK');
      },
      isToday(date) {
        const created_at_val = new Date(date);
        const today = new Date();
        return created_at_val.toDateString() === today.toDateString();
      },
      toLocalTimeHours: (date) => {
        return new Date(date).toLocaleTimeString('da-DK', {hour: '2-digit', minute: '2-digit'});
      },
      getDateWeekdayNumber: (date) => {
        const created_at_val = new Date(date);
        const weekday = created_at_val.getDay();
        return weekday === 0 ? 7 : weekday;
      },
      weekdayNumbers: {
        monday: 1,
        tuesday: 2,
        wednesday: 3,
        thursday: 4,
        friday: 5,
        saturday: 6,
        sunday: 7,
      },
      getDateMonthStart() {
        return new Date(new Date().getFullYear(), new Date().getMonth(), 1);
      },
      getDateMonthEnd() {
        return new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0);
      },
      getDateMonthName(date) {
        console.log(date)
        return new Date(date).toLocaleString('da-DK', { month: 'long' });
      },
      getDateYear(date) {
        return new Date(date).getFullYear();
      },
      getDateAtTime(date, hours, minutes, seconds) {
        const newDate = new Date(date);
        newDate.setHours(hours);
        newDate.setMinutes(minutes);
        newDate.setSeconds(seconds);
        return newDate;
      },
      getWeekdayNameToLocal(date) {
        return new Date(date).toLocaleString('da-DK', { weekday: 'long' });
      }
    },
    /** Redirect to */
    redirectTo: {
      /**
       * Pages to redirect to
       */
      pages: {
        login: () => {
          window.location.href = '/login';
        },
      },
      /**
       * Redirect to a department
       * @note This will redirect the user to '/admin/:department(/:path)'
       * @param department The department id
       * @param path The path to redirect to (Optional)
       * @param new_tab Open the url in a new tab
       */
      department: (department, path = null, new_tab = false) => {
        if (new_tab) {
          window.open('/admin/' + department + (path !== null ? '/' + path : ''), '_blank');
          return;
        }
        window.location.href = '/admin/' + department + (path !== null ? '/' + path : '');
      },
      /**
       * Redirect to a superuser page
       * @note This will redirect the user to '/superuser(/:path)'
       * @param path The path to redirect to (Optional)
       * @param new_tab Open the url in a new tab
       */
      superUser: (path = null, new_tab = false) => {
        if (new_tab) {
          window.open('/superuser' + (path !== null ? path : ''), '_blank');
          return;
        }
        window.location.href = '/superuser' + (path !== null ? path : '');
      },
      /**
       * Redirect to a user page
       * @note This will redirect the user to '/user(/:path)'
       * @param path The path to redirect to (Optional)
       */
      user: (path = null) => {
        window.location.href = '/user' + (path !== null ? path : '');
      },
      /**
       * External redirect
       * @param url The url to redirect to
       * @param newTab Open the url in a new tab
       */
      external: (url, newTab = false) => {
        if (newTab) {
          window.open(url, '_blank');
        } else {
          window.location.href = url;
        }
      },
    },
    parseErrorMessage(error) {
      console.log('Parsing error message: ', error);
      // Check if the error is a string
      if (typeof error === 'string') {
        return error;
      }
      // check if the response.data.data.message exists
      if (error.response && error.response.data && error.response.data.data && error.response.data.data.message) {
        return error.response.data.data.message;
      }
      // check if the response.data.message exists
      if (error.response && error.response.data && error.response.data.message) {
        return error.response.data.message;
      }
      // check if the response.data exists
      if (error.response && error.response.data) {
        return error.response.data;
      }
      // check if the response exists
      if (error.response) {
        return error.response;
      }
    }
  },
  request: authenticatedRequest,
  editField: EditFieldForm,
  getSessionData: getSessionData,
  initiateOnAppStart: initiateOnAppStart
};

</script>