<?php

/**
 * Renderiza um metabox a partir das configurações e função fornecidas.
 *
 * @param array $settings Configurações do metabox.
 *                        As configurações aceitam os seguintes parâmetros:
 *   - 'title' (string): O título do metabox personalizado. Padrão é 'Campo personalizado'.
 *   - 'screen' (string): O nome da tela onde o metabox será exibido. Padrão é 'page'.
 *   - 'context' (string): O contexto em que o metabox será exibido. Padrão é 'normal'.
 *   - 'priority' (string): A prioridade de exibição do metabox. Padrão é 'high'.
 *   - 'slug' (string): O slug da postagem em que o metabox deve ser exibido (opcional).
 *   - 'id' (int): O ID da postagem em que o metabox deve ser exibido (opcional).
 *   - 'file' (string): O slug do template da página em que o metabox deve ser exibido (opcional).
 *   - 'compare' (string): A comparação a ser feita se o metabox deve ser exibido ou não. Opções são 'IN' ou 'NOT IN' (opcional).
 *   - 'remove_supports' (array): Um array contendo os recursos (supports) a serem removidos da postagem (opcional).
 * @param mixed $callback A função de callback que renderiza o conteúdo do metabox personalizado.
 */
function o2_metabox($settings, $callback) {
  $metabox_settings = [
    'title'    => 'Campo personalizado',
    'screen'   => 'page',
    'context'  => 'normal',
    'priority' => 'high'
  ];
  $metabox_settings = array_merge($metabox_settings, $settings);

  $id = Helper::get_the_ID();
  $post = get_post($id);

  if (isset($metabox_settings['slug'])) {
    $metabox_settings['should_display'] = Helper::check_value(get_post_field('post_name', $post), $metabox_settings['slug']);
  } elseif (isset($metabox_settings['id'])) {
    $metabox_settings['should_display'] = Helper::check_value($id, $metabox_settings['id']);
  } elseif (isset($metabox_settings['file'])) {
    $metabox_settings['should_display'] = Helper::check_value(get_page_template_slug($id), $metabox_settings['file']);
  } else {
    $metabox_settings['should_display'] = true;
  }

  if (isset($metabox_settings['compare']) && $metabox_settings['compare'] == 'NOT IN') {
    $metabox_settings['should_display'] = !$metabox_settings['should_display'];
  }

  if ($metabox_settings['should_display'] && isset($settings['remove_supports']) && isset($post->ID)) {
    o2_remove_supports('id', $post->ID, $settings['remove_supports']);
  }

  new Metabox(
    MetaboxController::get_prefix(),
    $metabox_settings['title'],
    $callback,
    $metabox_settings['screen'],
    $metabox_settings['context'],
    $metabox_settings['priority'],
    $metabox_settings['should_display']
  );
}

/**
 * Cria um metabox personalizado que será exibido logo após o título da postagem no editor do WordPress.
 *
 * @param array $settings Configurações do metabox personalizado.
 * @param callable $callback Função de callback que renderiza o conteúdo do metabox.
 */
function o2_metabox_after_title($settings, $callback) {
  $metabox_settings = array_merge($settings, ['context' => 'after_title']);
  o2_metabox($metabox_settings, $callback);
}

/**
 * Cria um metabox personalizado para uma taxonomia específica.
 *
 * @param string $title Título do metabox personalizado.
 * @param string $taxonomy Taxonomia à qual o metabox será associado.
 * @param callable $callback Função de callback que renderiza o conteúdo do metabox.
 */
function o2_metabox_taxonomy($title, $taxonomy, $callback) {
  new TaxonomyMetabox(
    MetaboxController::get_prefix(),
    $taxonomy,
    $title,
    $callback
  );
}

/**
 * Renderiza uma repetição simples com base nas configurações fornecidas e na função de callback.
 *
 * @param string   $key        Chave para identificar a repetição.
 * @param string   $type       Tipo da repetição (array/matrix).
 * @param mixed    $callback   A função que será renderizada para cada repetição.
 */
function o2_repeat($label, $key, $type, $callback) {
  $qtd = $type === 'array' ? 1 : 2;

  if (Group::in_group()) // Caso esteja dentro de um Group, configurar a repetição
    Repeat::set_data(Group::init_repeat());

  printf('
        <div class="mb-3">
          <span class="form-label">%s</span>
          <div class="o2-repeat o2-repeat-simple">
              <div class="o2-repeat-wrapper">
    ', $label);

  Repeat::render($key, $qtd, function () use ($callback) {
    echo '<div class="o2-repeat-item">';
    echo '  <div class="d-flex align-items-center">';
    echo '    <div class="flex-fill">';
    call_user_func($callback);
    echo '    </div>';
    echo '    <div class="ps-3">';
    echo '      <button type="button" title="Remover" class="o2-repeat-simple-remove o2-repeat-remove" tabindex="-1"><span class="material-icons">close</span></button>';
    echo '    </div>';
    echo '  </div>';
    echo '</div>';
  });

  if (Group::in_group())
    Repeat::set_data(array());

  $model = Repeat::renderModel($key, $qtd, function () use ($callback) {
    echo '<div class="o2-repeat-item">';
    echo '  <div class="d-flex align-items-center">';
    echo '    <div class="flex-fill">';
    call_user_func($callback);
    echo '    </div>';
    echo '    <div class="ps-3">';
    echo '      <button type="button" title="Remover" class="o2-repeat-simple-remove o2-repeat-remove" tabindex="-1"><span class="material-icons">close</span></button>';
    echo '    </div>';
    echo '  </div>';
    echo '</div>';
  });

  printf('
              </div>
              <button type="button" title="Adicionar" class="o2-button o2-button-icon o2-button-blue o2-repeat-add">
                Adicionar item
                <span class="material-icons">add</span>
              </button>
              <input class="o2-repeat-item-model" type="hidden" value="%s" />
          </div>
        </div>
    ', htmlspecialchars($model));
}

/**
 * Renderiza uma repetição com accordion com base nas configurações fornecidas e na função de callback.
 *
 * @param string   $key       Chave para identificar a repetição.
 * @param string   $type      Tipo da repetição (array/matrix).
 * @param mixed    $callback     A função que será renderizada para cada repetição.
 */
function o2_repeat_accordion($label, $key, $type, $callback) {
  $qtd = $type === 'array' ? 1 : 2;

  if (Group::in_group()) // Caso esteja dentro de um Group, configurar a repetição
    Repeat::set_data(Group::init_repeat());

  printf('
    <div class="mb-3">
      <span class="form-label">%s</span>
      <div class="o2-repeat o2-repeat-accordion">
          <div class="o2-repeat-wrapper">
  ', $label);

  Repeat::render($key, $qtd, function ($index) use ($callback) {
    echo '<div class="o2-repeat-item">';

    printf('
            <div class="o2-repeat-item-head">
                <div class="o2-repeat-item-head-left">
                    <span class="o2-repeat-item-title">Item</span>
                </div>

                <div class="o2-repeat-item-head-right">
                    <button type="button" title="Adicionar item abaixo" class="o2-repeat-add-down"><span class="material-icons">add</span></button>
                    <div class="o2-repeat-item-indicator"><span class="material-icons">arrow_drop_down</span></div>
                    <button type="button" title="Remover item" class="o2-repeat-remove"><span class="material-icons">close</span></button>
                </div>
            </div>
        ');

    echo '<div class="o2-repeat-item-body hidden">';
    call_user_func($callback);
    echo '</div>';

    echo '</div>';
  });

  $model = Repeat::renderModel($key, $qtd, function () use ($callback) {
    echo '<div class="o2-repeat-item">';
    printf('
            <div class="o2-repeat-item-head">
                <div class="o2-repeat-item-head-left">
                    <span class="o2-repeat-item-title">Item</span>
                </div>

                <div class="o2-repeat-item-head-right">
                    <button type="button" title="Adicionar item abaixo" class="o2-repeat-add-down"><span class="material-icons">add</span></button>
                    <div class="o2-repeat-item-indicator"><span class="material-icons">arrow_drop_down</span></div>
                    <button type="button" title="Remover item" class="o2-repeat-remove"><span class="material-icons">close</span></button>
                </div>
            </div>
        ');
    echo '<div class="o2-repeat-item-body hidden">';
    call_user_func($callback);
    echo '</div>';
    echo '</div>';
  });

  printf('
          </div>
          <button type="button" title="Adicionar" class="o2-button o2-button-icon o2-button-blue o2-repeat-add">
            Adicionar item
            <span class="material-icons">add</span>
          </button>
          <input class="o2-repeat-item-model" type="hidden" value="%s" />
      </div>
    </div>
  ', htmlspecialchars($model));

  if (Group::in_group())
    Repeat::set_data(array());
}

/**
 * Renderiza um grupo repetível com elementos arrastáveis com base nas configurações fornecidas e na função de callback.
 * 
 * @param string   $key      A chave para identificar o grupo repetível.
 * @param string   $type      Tipo da repetição (array/matrix).
 * @param mixed $callback A função que será renderizada para cada item do grupo.
 */
function o2_repeat_draggable($label, $key, $type, $callback) {
  $qtd = $type === 'array' ? 1 : 2;

  if (Group::in_group()) // Caso esteja dentro de um Group, configurar a repetição
    Repeat::set_data(Group::init_repeat());
  printf('
    <div class="mb-3">
      <span class="form-label">%s</span>
      <div class="o2-repeat o2-repeat-simple draggable">
          <div class="o2-repeat-wrapper">
  ', $label);

  Repeat::render($key, $qtd, function () use ($callback) {
    echo '<div class="o2-repeat-item">';
    echo '  <div class="d-flex align-items-center">';
    echo '    <div class="o2-repeat-handle"><span class="material-icons">menu</span></div>';
    echo '    <div class="flex-fill">';
    call_user_func($callback);
    echo '    </div>';
    echo '    <div class="ps-3">';
    echo '      <button type="button" title="Remover" class="o2-repeat-simple-remove o2-repeat-remove" tabindex="-1"><span class="material-icons">close</span></button>';
    echo '    </div>';
    echo '  </div>';
    echo '</div>';
  });

  $model = Repeat::renderModel($key, $qtd, function () use ($callback) {
    echo '<div class="o2-repeat-item">';
    echo '  <div class="d-flex align-items-center">';
    echo '    <div class="o2-repeat-handle"><span class="material-icons">menu</span></div>';
    echo '    <div class="flex-fill">';
    call_user_func($callback);
    echo '    </div>';
    echo '    <div class="ps-3">';
    echo '      <button type="button" title="Remover" class="o2-repeat-simple-remove o2-repeat-remove" tabindex="-1"><span class="material-icons">close</span></button>';
    echo '    </div>';
    echo '  </div>';
    echo '</div>';
  });

  printf('
          </div>
          <button type="button" title="Adicionar" class="o2-button o2-button-icon o2-button-blue o2-repeat-add">
            Adicionar item
            <span class="material-icons">add</span>
          </button>
          <input class="o2-repeat-item-model" type="hidden" value="%s" />
      </div>
    </div>
  ', htmlspecialchars($model));

  if (Group::in_group())
    Repeat::set_data(array());
}

/**
 * Renderiza um grupo repetível com elementos arrastáveis e estilo de acordeão com base nas configurações fornecidas e na função de callback.
 * 
 * @param string   $key      A chave para identificar o grupo repetível.
 * @param string   $type      Tipo da repetição (array/matrix).
 * @param mixed $callback A função que será renderizada para cada item do grupo.
 */
function o2_repeat_accordion_draggable($label, $key, $type, $callback) {
  $qtd = $type === 'array' ? 1 : 2;

  if (Group::in_group()) // Caso esteja dentro de um Group, configurar a repetição
    Repeat::set_data(Group::init_repeat());

  printf('
    <div class="mb-3">
      <span class="form-label">%s</span>
      <div class="o2-repeat o2-repeat-accordion draggable">
          <div class="o2-repeat-wrapper">
  ', $label);

  Repeat::render($key, $qtd, function ($index) use ($callback) {
    echo '<div class="o2-repeat-item">';

    printf('
            <div class="o2-repeat-item-head">
                <div class="o2-repeat-item-head-left">
                  <div class="o2-repeat-handle"><span class="material-icons">menu</span></div>
                  <span class="o2-repeat-item-title">Item</span>
                </div>

                <div class="o2-repeat-item-head-right">
                    <button type="button" title="Adicionar item abaixo" class="o2-repeat-add-down"><span class="material-icons">add</span></button>
                    <div class="o2-repeat-item-indicator"><span class="material-icons">arrow_drop_down</span></div>
                    <button type="button" title="Remover item" class="o2-repeat-remove"><span class="material-icons">close</span></button>
                </div>
            </div>
        ');

    echo '<div class="o2-repeat-item-body hidden">';
    call_user_func($callback);
    echo '</div>';

    echo '</div>';
  });

  $model = Repeat::renderModel($key, $qtd, function () use ($callback) {
    echo '<div class="o2-repeat-item">';
    printf('
            <div class="o2-repeat-item-head">
                <div class="o2-repeat-item-head-left">
                  <div class="o2-repeat-handle"><span class="material-icons">menu</span></div>
                  <span class="o2-repeat-item-title">Item</span>
                </div>

                <div class="o2-repeat-item-head-right">
                    <button type="button" title="Adicionar item abaixo" class="o2-repeat-add-down"><span class="material-icons">add</span></button>
                    <div class="o2-repeat-item-indicator"><span class="material-icons">arrow_drop_down</span></div>
                    <button type="button" title="Remover item" class="o2-repeat-remove"><span class="material-icons">close</span></button>
                </div>
            </div>
        ');
    echo '<div class="o2-repeat-item-body hidden">';
    call_user_func($callback);
    echo '</div>';
    echo '</div>';
  });

  printf('
          </div>
          <button type="button" title="Adicionar" class="o2-button o2-button-icon o2-button-blue o2-repeat-add">
            Adicionar item
            <span class="material-icons">add</span>
          </button>
          <input class="o2-repeat-item-model" type="hidden" value="%s" />
      </div>
    </div>
  ', htmlspecialchars($model));

  if (Group::in_group())
    Repeat::set_data(array());
}

/**
 * Função responsável por definir qual o label do repeat, usado apenas para os accordion
 * 
 * @param string   $key      A chave para identificar o campo.
 * @param string   $type     O tipo do campo. (text, textarea, select, link, image)
 */
function o2_repeat_set_label($key, $type) {
  $args = array(
    'name' => Helper::get_name($key),
    'type' => $type
  );

  $attributes = array(
    'class' => 'o2-repeat-set-label',
    'value' => json_encode($args),
    'type' => 'hidden'
  );

  echo Input::render($attributes);
}

/**
 * Renderiza um grupo com base nas configurações fornecidas e na função de callback.
 * 
 * @param string   $label    O rótulo do grupo.
 * @param string   $key      A chave para identificar o grupo.
 * @param mixed $callback A função que será renderizada no grupo.
 */
function o2_group($label, $key, $callback) {
  echo '<div class="o2-group mb-3">';
  printf('<span class="o2-group-label">%s</span>', $label);

  if (Repeat::in_loop())
    Repeat::init_group($key, $callback);
  else
    Group::render($key, $callback);

  echo '</div>';
}

/**
 * Renderiza uma tab com base na função de callback fornecida.
 * 
 * @param mixed $callback A função que será renderizada na tab.
 */
function o2_tab($callback) {
  tab::render($callback);
}

/**
 * Cria uma nova tab com o rótulo fornecido e a função de callback.
 * 
 * @param string   $label    O rótulo da tab.
 * @param mixed $callback A função que será renderizada na tab.
 */
function o2_tab_create($label, $callback) {
  tab::create_tab($label, $callback);
}

/**
 * Cria um estrutura que irá tratar exibição condicional de acordo com as configurações passadas.
 * 
 * Parâmetros esperados:
 * - 'field' (string): Tipo do field (radio/select).
 * - 'key' (string): Chave do field.
 * - 'condition' (mixed): Valor esperado para exibir a estrutura.
 * 
 * @param array $args Configuração da exibição.
 * @param mixed $callback Função com o conteúdo.
 */
function o2_conditional_diyplay($args, $callback) {
  $key = o2_get_name($args['key']);

  $data = [
    'field' => $args['field'],
    'key' => $key,
    'condition' => $args['condition']
  ];

  $dataText = [];
  foreach ($data as $key => $value)
    $dataText[] = sprintf('data-conditional-%s="%s"', $key, $value);

  echo '<div class="o2-conditional-display" style="display: none" ' . implode(' ', $dataText) . '>';
  call_user_func($callback);
  echo '</div>';
}

/**
 * Exibe uma observação para guiar os usuários
 * 
 * @param string $text Texto da observação
 */
function o2_note($text) {
  printf('<div class="o2-note mb-3"><b>Observação:</b> %s</div>', stripslashes($text));
}

/**
 * Remove suportes (supports) específicos de uma postagem ou taxonomia.
 *
 * @param string $type Tipo de item a ser modificado. Pode ser 'id' para postagens ou 'taxonomy' para taxonomias.
 * @param int|string $needle ID da postagem ou slug da taxonomia a ser modificada.
 * @param array $features Array contendo os suportes a serem removidos.
 */
function o2_remove_supports($type, $needle, $features) {
  new SupportRemover($type, $needle, $features);
}

/**
 * Retorna o name de um campo personalizado
 * 
 * @param string $key Chave associada ao campo personalizado.
 * @return string Chave associada modificada em caso de repetições ou grupo.
 */
function o2_get_name($key) {
  return Helper::get_name($key);
}

/**
 * Retorna o name de um campo personalizado
 * 
 * @param string $key Chave associada ao campo personalizado.
 * @return string Valor associado a chave fornecida recuperada do banco de dados.
 */
function o2_get_value($key) {
  return Helper::get_value($key);
}

/**
 * Retorna os atributos associados a um campo personalizado.
 *
 * @param string $key Chave associada ao campo personalizado.
 * @return array Array contendo os atributos associados ao campo personalizado.
 */
function o2_get_attr($key) {
  return Helper::get_attr($key);
}

/**
 * Adiciona uma lista de chaves de campos personalizados para serem salvos no banco de dados.
 *
 * @param array|string $field Lista de chaves de campos personalizados a serem adicionados.
 *                            Pode ser um array contendo várias chaves ou uma string representando uma única chave.
 *                            Cada chave representa um campo personalizado onde os dados serão salvos no banco de dados.
 */
function o2_add_field($field) {
  if (is_array($field)) {
    // Se for um array, percorre as chaves e salva cada uma delas usando a função Helper::save_field.
    foreach ($field as $f) {
      Helper::save_field($f);
    }
  } else {
    // Se for uma string, salva a chave única usando a função Helper::save_field.
    Helper::save_field($field);
  }
}
