import { Model, Query } from '@vuex-orm/core'
import { Ability } from '@casl/ability'
import { Store } from 'vuex'
import { Context } from '@nuxt/types/app'
import DataPersister from '~/services/data/dataPersister'
import DataProvider from '~/services/data/dataProvider'
import DataDeleter from '~/services/data/dataDeleter'
import {ABILITIES, FORM_STATUS, GENDER, METADATA_TYPE, QUERY_TYPE, SUBMIT_TYPE, TYPE_ALERT} from '~/types/enums'

/**
 * Upgrade du @nuxt/types pour TypeScript
 */
declare module '@nuxt/types' {
  interface Context {
    $ability: Ability,
    $dataPersister: DataPersister,
    $dataProvider: DataProvider,
    $dataDeleter: DataDeleter,
  }
}

declare module '@vuex-orm/core' {
  interface Query{
    getAllRelations: () => Array<string>
  }
}

interface ItemMenu {
  title: string,
  icon?: string,
  to?: string,
  children?: ItemsMenu,
  isExternalLink?: boolean,
  actions?: ItemsMenu,
}
interface ItemsMenu extends Array<ItemMenu> {}

interface Menu {
  getMenu : () => ItemMenu | null,
  getHeaderMenu : () => ItemMenu | null,
}

interface AbilitiesType {
  action: ABILITIES,

  subject: string,
  /** an array of fields to which user has (or not) access */
  fields?: string[]
  /** an object of conditions which restricts the rule scope */
  conditions?: any
  /** indicates whether rule allows or forbids something */
  inverted?: boolean
  /** message which explains why rule is forbidden */
  reason?: string
}

interface formState {
  violations: Array<string>,
  readonly: boolean,
  formStatus: FORM_STATUS,
  dirty: boolean,
  showConfirmToLeave: boolean,
  goAfterLeave: string
}

interface Alert {
  type: TYPE_ALERT,
  messages: Array<string>
}

interface pageState {
  alerts: Array<Alert>,
}

interface Historical {
  future?: boolean,
  past?: boolean,
  present?: boolean,
  dateStart?: string,
  dateEnd?: string
}

interface baseAccessState {
  id: number,
  name: string,
  givenName: string,
  gender: GENDER,
  avatarId: number
}

interface OrignalAccessState extends baseAccessState {
  isSuperAdminAccess: boolean,
  organization: baseOrganizationState
}

interface accessState extends baseAccessState {
  bearer: string,
  switchId: number,
  activityYear: number,
  historical: Historical,
  roles: Array<string>,
  abilities: Array<AbilitiesType>,
  isAdminAccess: boolean,
  isSuperAdminAccess: boolean,
  isAdmin: boolean,
  isAdministratifManager: boolean,
  isPedagogicManager: boolean,
  isFinancialManager: boolean,
  isCaMember: boolean,
  isStudent: boolean,
  isTeacher: boolean,
  isMember: boolean,
  isOther: boolean,
  isGuardian: boolean,
  isPayor: boolean,
  hasLateralMenu: boolean,
  hasConfigurationMenu: boolean,
  hasAccessesMenu: boolean,
  hasFamilyMenu: boolean,
  multiAccesses: Array<baseOrganizationState>,
  familyAccesses: Array<baseAccessState>,
  originalAccess: OrignalAccessState
}

interface AccessStore extends Store<{profile:{access: accessState}}> {}

interface baseOrganizationState {
  id: number,
  name: string,
  website?: string,
  subDomain?: string
}

interface organizationState extends baseOrganizationState {
  id: number,
  name: string,
  product?: string,
  currentActivityYear?: number,
  modules?: Array<string>,
  hasChildren?: boolean,
  showAdherentList?: boolean,
  networks: Array<string>,
  parents: Array<organizationState>,
}
interface OrganizationStore extends Store<{profile:{organization: organizationState}}> {}

interface AnyJson extends Record<string, any> {}
interface AnyStore extends Store<any> {}

interface EnumChoice {
  value: string,
  label: string
}

interface UrlArgs {
  readonly type: QUERY_TYPE,
  readonly url?: string,
  readonly baseUrl?: string,
  readonly enumType?: string,
  readonly model?: typeof Model,
  readonly rootModel?: typeof Model,
  readonly id?: any,
  readonly idTemp?: any,
  readonly rootId?: number,
  readonly showProgress?: boolean,
  readonly hook?: string,
  readonly params?: AnyJson
}

interface ImageArgs {
  readonly id: number,
  readonly height: number,
  readonly width: number
}

interface Filter{
  readonly key: string,
  readonly value: string|boolean|number
}

interface ListArgs {
  readonly itemsPerPage?: number,
  readonly page?: number
  readonly filters?: Array<Filter>
}

interface DataProviderArgs extends UrlArgs {
  imgArgs?: ImageArgs,
  listArgs?: ListArgs,
}
interface DataPersisterArgs extends UrlArgs {
  data?: AnyJson,
  query?: Query,
  file?: string
}
interface DataDeleterArgs extends UrlArgs {}

interface EnumChoices extends Array<EnumChoice> {}

interface DataManager {
  initCtx(ctx: Context): void,
  invoke(args: UrlArgs): Promise<any>,
}

interface HookProvider {
  invoke(args: DataProviderArgs): Promise<any>,
}
interface HookPersister {
  invoke(args: DataPersisterArgs): Promise<any>,
}
interface HookDeleter {
  invoke(args: DataDeleterArgs): Promise<any>,
}

interface Processor {
  process(data: AnyJson): Promise<any>
}

interface Normalizer {
  normalize(args: DataPersisterArgs): any,
}
interface Denormalizer {
  denormalize(data: any): any,
}

interface DolibarrContractLine {
  id: number,
  contractId: number,
  dateStart: Date,
  dateEnd: Date,
  serviceRef: string,
  serviceLabel: string
}

interface DolibarrContract {
  ref: string,
  socId: number,
  lines: Array<DolibarrContractLine>
}

interface DolibarrBill {
  id: number,
  ref: string,
  socId: number,
  date: Date,
  taxExcludedAmount: number,
  taxIncludedAmount: number,
  paid: boolean
}

interface DolibarrAccount {
  organizationId: number,
  socId: number,
  clientNumber: string,
  product: 'PRODUCT_ARTIST' | 'PRODUCT_ARTIST_PREMIUM' | 'PRODUCT_SCHOOL' |
           'PRODUCT_SCHOOL_PREMIUM' | 'PRODUCT_MANAGER',
  contract: DolibarrContract,
  bills: Array<DolibarrBill>
}

interface MobytUserStatus {
  organizationId: number,
  active: boolean,
  amount: number,
  money: number
}

interface ApiResponse{
  data: AnyJson,
  metadata: HydraMetadata
}

interface HydraMetadata {
  readonly totalItems?: number,
  firstPage?: number,
  lastPage?: number,
  nextPage?: number,
  previousPage?: number,
  type?: METADATA_TYPE
}

