import { DirectiveSchema } from '../types';

import { logger, parseExpression } from '../../utils';

function vExpression(
  directives: Record<string, DirectiveSchema> = {},
  context: any,
  name: string,
  defaultValue: any
) {
  const directive = directives[name];
  if (!directive || !directive.value) return defaultValue;
  return parseExpression(directive.value, context);
}

/**
 * v-if 指令
 * @param directives
 * @param context
 * @returns
 */
export function vIf(
  directives: Record<string, DirectiveSchema> = {},
  context: any
) {
  return !!vExpression(directives, context, 'v-if', true);
}

/**
 * v-show 指令
 * @param directives
 * @param context
 * @returns
 */
export function vShow(
  directives: Record<string, DirectiveSchema> = {},
  context: any
) {
  return !!vExpression(directives, context, 'v-show', true);
}

export function hasVShow(directives: Record<string, DirectiveSchema> = {}) {
  return !!directives['v-show'];
}

export function vOn(
  directives: Record<string, DirectiveSchema> = {},
  context: any
) {
  return vExpression(directives, context, 'v-on', null);
}

export function vBind(
  directives: Record<string, DirectiveSchema> = {},
  context: any
) {
  return vExpression(directives, context, 'v-bind', null);
}

/**
 * 双向绑定
 * @param directives
 * @param context
 * @returns
 */
export function vModel(
  directives: Record<string, DirectiveSchema> = {},
  context: any
) {
  const directive = directives['v-model'];
  if (!directive || !directive.value) return null;
  return {
    // 表达式要用this，否则会引发警告
    modelValue: parseExpression(directive.value, context),
    'onUpdate:modelValue': (v: string) => {
      try {
        const content = `${directive.value?.value} = ${JSON.stringify(v)}`;
        const exp = {
          type: 'JSExpression',
          value: content
        };
        parseExpression(exp, context);
      } catch (e) {
        logger.warn(e);
      }
    }
  };
}

export function vFor(
  id: string,
  directives: Record<string, DirectiveSchema> = {},
  context: any,
  callback: (item?: any, index?: string | number) => void
) {
  const directive = directives['v-for'];
  if (!directive || !directive.value) return callback();
  const { item = 'item', index = 'index' } = directive.extend || {};
  const data = parseExpression(directive.value, context);
  if (typeof data !== 'object') return callback();
  const result = [];
  for (let name in data) {
    const iterator = {
      [item]: data[name],
      [index]: name
    };
    if (!context.context[id]) {
      context.context[id] = {};
    }
    Object.assign(context.context[id], iterator);
    result.push(callback(iterator));
  }
  return result;
}
