<?php

if (!function_exists("const_or_default")) {
  function const_or_default($constant_name, $default = null)
  {
    return defined($constant_name) ? constant($constant_name) : $default;
  }
}

function rwmb_remove_field($mb, $id)
{
  return array_reduce(
    $mb["fields"],
    function ($result, $field) use ($id) {
      $field_id = $field["id"] ?? null;
      if ($field_id != $id) {
        $result[] = $field;
      }
      return $result;
    },
    [],
  );
}

/**
 * Returns first element of array or default value if result array is empty.
 *
 * @param array $array
 * @param callable $filter_callback
 * When the $filter_callback is provided, only value matching the filter will be returned.
 * If none of the array items is matchnig the callback, the result will be default value.
 * @param mixed $default_value
 *
 * Usage
 * ```
 * $arr = ["asd", "sds", "cdf", "res"];
 * $first = array_first_or_default($arr); // "asd"
 * $starts_with_c = array_first_or_default($arr, fn($text) => str_starts_with($text, "c")); // "cdf"
 * ```
 */
function array_first_or_default(
  $array,
  $filter_callback = null,
  $default_value = null
) {
  if (!$array || !count($array)) {
    return $default_value;
  }
  if (!$filter_callback) {
    return reset($array);
  }
  foreach ($array as $value) {
    if (call_user_func($filter_callback, $value)) {
      return $value;
    }
  }
  return $default_value;
}

function inoby_img_size($name)
{
  return Inoby_Config::image_sizes()[$name] ?? [];
}

function inoby_image(
  $url,
  $img_size,
  $alt,
  $attrs = [],
  $lazy = true,
  $high_priority = false,
  $echo = false
) {
  $size = inoby_img_size($img_size);
  $w = $size["width"] ?? null;
  $h = $size["height"] ?? null;

  $default = [
    "src" => $url,
    "decoding" => "async",
    "alt" => $alt,
  ];
  if ($w) {
    $default["width"] = $w;
  }
  if ($h) {
    $default["height"] = $h;
  }
  if ($lazy) {
    $default["loading"] = "lazy";
  }
  if ($high_priority) {
    $default["fetchpriority"] = "high";
  }
  $img = "<img " . __attr(wp_parse_args($attrs, $default)) . "/>";
  if (!$echo) {
    return $img;
  }
  echo $img;
}

// prettier-ignore
/**
 * @deprecated
 */
function inoby_picture($attachment_id, $attr = [])
{

  $attr = array_merge($attr, [
    "sm" => (isset($attr["sm"]) ? $attr["sm"] . "" : "") . "",
    "md" => (isset($attr["md"]) ? $attr["md"] . "" : "") . "",
    "lg" => (isset($attr["lg"]) ? $attr["lg"] . "" : "") . "",
    "xl" => (isset($attr["xl"]) ? $attr["xl"] . "" : "") . "",
    "xxl" => (isset($attr["xl"]) ? $attr["xxl"] . "" : "") . "",
    "full" => (isset($attr["full"]) ? $attr["full"] . "" : "") . "",
  ]);

  $alt = _wp_specialchars(get_post_field("post_title", $attachment_id), ENT_QUOTES, "UTF-8", true);
  $full_src = wp_get_attachment_image_src($attachment_id, $attr['full']);
  $sm_src = wp_get_attachment_image_src($attachment_id, $attr['sm']);
  $md_src = wp_get_attachment_image_src($attachment_id, $attr['md']);
  $lg_src = wp_get_attachment_image_src($attachment_id, $attr['lg']);
  $xl_src = wp_get_attachment_image_src($attachment_id, $attr['xl']);
  $xxl_src = wp_get_attachment_image_src($attachment_id, $attr['xxl']);

  return '<picture>
    <source media="(min-width: 2560px)" srcset="' . $full_src[0] . '">
    <source media="(min-width: 1920px) and (max-width: 2559px)" srcset="' . $xxl_src[0] . '">
    <source media="(min-width: 1440px) and (max-width: 1919px)" srcset="' . $xl_src[0] . '">
    <source media="(min-width: 1024px) and (max-width: 1439px)" srcset="' . $lg_src[0] . '">
    <source media="(min-width: 768px) and (max-width: 1023px)" srcset="' . $md_src[0] . '">
    <img src="' . $sm_src[0] . '" alt="' . $alt . '">
  </picture>';
}

/**
 * Outputs image width defined sizes based on provided breakpoints
 * @param $mb array Metabox image or image ID
 * @param $default_size string Default Image size
 * @param $bp_sizes array array with breakpoints as a keys and image sizes as values
 * ```
 * ["sm" => "small", "md" => "medium", "lg" => "full"]
 * ```
 */
function mb_inoby_picture(
  $mb,
  $default = "thumbnail",
  $bp_sizes = [],
  $br = 0,
  $alt = null,
  $lazy = true
) {
  $image = reset($mb);
  if (is_numeric($image)) {
    $image = RWMB_Image_Field::file_info($image);
  }
  $breakpoints = Inoby_Config::breakpoints();
  $alt = $alt ?: ($image["alt"] ?: $image["title"]);

  echo "<picture>";
  foreach ($bp_sizes as $bp => $image_size) {
    $max = $breakpoints[$bp]["max-width"];
    $min = $breakpoints[$bp]["min-width"];
    $url = $image["sizes"][$image_size]["url"];
    $source =
      '<source media="(min-width: ' .
      $min .
      "px) and (max-width: " .
      $max .
      'px)" srcset="' .
      $url .
      '">';
    echo $source;
  }
  $default_url = $image["sizes"][$default]["url"];
  $width = $image["sizes"][$default]["width"] ?: $image["width"];
  $height = $image["sizes"][$default]["height"] ?: $image["height"];

  echo inoby_image(
    $default_url,
    "",
    $alt,
    [
      "style" => "width: 100%; border-radius: {$br}px;",
      "width" => $width,
      "height" => $height,
    ],
    $lazy,
    !$lazy,
  );
  echo "</picture>";
  return;
}

function inoby_parse_args($args, $defaults = [], $cast_types = false)
{
  $parsed = wp_parse_args($args, $defaults);
  if ($cast_types) {
    foreach ($parsed as $key => $value) {
      if (isset($defaults[$key])) {
        $type = gettype($defaults[$key]);
        switch ($type) {
          case "boolean":
            $parsed[$key] = boolval($value);
            break;
          case "integer":
            $parsed[$key] = intval($value);
            break;
          case "double":
            $parsed[$key] = floatval($value);
            break;
          case "string":
            $parsed[$key] = strval($value);
            break;
          default:
            break;
        }
      }
    }
  }

  return $parsed;
}

function array_to_html_attrs($attrs, $escape = false)
{
  return implode(
    " ",
    array_map(
      function ($k, $v) use ($escape) {
        return $k . '="' . ($escape ? esc_attr($v) : $v) . '"';
      },
      array_keys($attrs),
      $attrs,
    ),
  );
}

function __attr($attrs, $escape = false)
{
  return array_to_html_attrs($attrs, $escape);
}

function __img($src, $width, $height, $alt, $lazy = true, $attrs = [])
{
  $attrs["src"] = $src;
  $attrs["width"] = $width;
  $attrs["height"] = $height;
  $attrs["alt"] = $alt;
  if ($lazy) {
    $attrs["loading"] = "lazy";
  }

  return "<img " . __attr($attrs) . ">";
}

function inoby_block_attrs($attributes, $attrs = [], $return = "string")
{
  $cls = $attrs["class"] ?? "";
  if (is_admin()) {
    $cls .= " is-preview";
  }

  if (!empty($attributes["className"] ?? "")) {
    $cls .= " {$attributes["className"]}";
  }

  if (!empty($attributes["align"] ?? "")) {
    $cls .= " align-{$attributes["align"]}";
  }

  $cls = trim(apply_filters("rwmb_block_classes", $cls, $attributes));
  if ($cls) {
    $attrs["class"] = $cls;
  }

  if (!empty($attributes["anchor"] ?? "")) {
    $attrs["id"] = $attributes["anchor"];
  }

  if ($return == "string") {
    return array_to_html_attrs($attrs, true);
  } elseif ($return == "object") {
    return (object) $attrs;
  }

  return $attrs;
}

function thumbnail_upscale($default, $orig_w, $orig_h, $new_w, $new_h, $crop)
{
  // if (!$crop) {
  //   return null;
  // } // let the wordpress default function handle this

  $aspect_ratio = $orig_w / $orig_h;
  if (!$new_h) {
    $new_h = $new_w / $aspect_ratio;
  }
  $size_ratio = max($new_w / $orig_w, $new_h / $orig_h);

  $crop_w = round($new_w / $size_ratio);
  $crop_h = round($new_h / $size_ratio);

  $s_x = floor(($orig_w - $crop_w) / 2);
  $s_y = floor(($orig_h - $crop_h) / 2);

  return [
    0,
    0,
    (int) $s_x,
    (int) $s_y,
    (int) $new_w,
    (int) $new_h,
    (int) $crop_w,
    (int) $crop_h,
  ];
}
add_filter("image_resize_dimensions", "thumbnail_upscale", 10, 6);

function posts_loadmore_ajax_handler()
{
  // prepare our arguments for the query
  $args = json_decode(stripslashes($_POST["query"]), true);
  $cardTemplate = $_POST["card_template"] ?? "" ?: "post-types/post/parts/card";
  $cardClasses = $_POST["card_classes"] ?? "" ?: "col-3 col-md-6 col-sm-12";
  if (Inoby_Config::latest_posts() > 0) {
    $current_page = max(1, $_POST["page"] + 1);
    $per_page = get_option("posts_per_page");
    $offset_start = Inoby_Config::latest_posts();
    $offset = ($current_page - 1) * $per_page + $offset_start;

    $args["paged"] = $_POST["page"] + 1; // we need next page to be loaded
    $args["offset"] = $offset; // we need next page to be loaded
  } else {
    $args["paged"] = $_POST["page"] + 1; // we need next page to be loaded
  }
  $args["post_status"] = "publish";
  // it is always better to use WP_Query but not here
  query_posts($args);
  if (have_posts()):
    // run the loop
    while (have_posts()):
      the_post();
      global $post;
      echo apply_filters(
        "inoby_post_list_card_before",
        "<div class=\"$cardClasses\">",
      );
      get_template_part($cardTemplate, null, ["post" => $post]);
      echo apply_filters("inoby_post_list_card_after", "</div>");
    endwhile;
  endif;
  die(); // here we exit the script and even no wp_reset_query() required!
}
add_action("wp_ajax_loadmore", "posts_loadmore_ajax_handler"); // wp_ajax_{action}
add_action("wp_ajax_nopriv_loadmore", "posts_loadmore_ajax_handler"); // wp_ajax_nopriv_{action}

function rwmb_meta_render_block($id, $data, $className = null, $echo = true)
{
  $block = [
    "blockName" => "meta-box/" . $id,
    "attrs" => [
      "id" => "mb-block-" . wp_hash(microtime()),
      "data" => $data,
      "className" => $className,
    ],
    "innerBlocks" => [],
    "innerHtml" => "",
    "innerContent" => [],
  ];
  $html = render_block($block);
  if ($echo) {
    echo $html;
  }
  return $html;
}

function rwmb_meta_render_reusable($block_name, $echo = true)
{
  if (!$echo) {
    ob_start();
  }

  global $wpdb;
  $block_id = $wpdb->get_var(
    "SELECT ID from {$wpdb->posts} WHERE post_type='wp_block' AND post_name='{$block_name}' AND post_status='publish'",
  );
  $block_id = apply_filters("rwmb_meta_render_reusable_block_id", $block_id);

  if ($block_id) {
    inoby_setup_postdata($block_id);
    the_content();
    inoby_reset_post_data();
  }
  if (!$echo) {
    return ob_get_clean();
  }
}

/**
 * Sluzi na to, ked chcem pouzivat funkcie ako the_title a podobne a potrebujem si nastavit nejaky svoj post
 * Po dokonceni prace s postom, napr. po zavolani template party, treba zavolat @see wp_reset_postdata()
 * @param WP_Post | int $post
 */
function inoby_setup_postdata($new_post)
{
  if (is_numeric($new_post)) {
    $new_post = get_post($new_post);
  }
  global $post;
  $post = $new_post;
  setup_postdata($new_post);
}

function inoby_reset_post_data()
{
  wp_reset_postdata();
}

/**
 * Validates Google reCAPTCHA v3 token
 * @param string $token The reCAPTCHA token from the frontend
 * @param float $score_threshold Minimum score to pass (0.0 to 1.0, default 0.5)
 * @return bool|WP_Error Returns true if valid, WP_Error if invalid or error occurred
 */
function inoby_validate_recaptcha($token, $score_threshold = 0.5)
{
  $secret_key = const_or_default("RECAPTCHA_SECRET_KEY", "");
  
  // If reCAPTCHA is not configured, skip validation
  if (empty($secret_key)) {
    return true;
  }
  
  // If no token provided, return error
  if (empty($token)) {
    return new WP_Error("recaptcha_missing", __("reCAPTCHA verification failed. Token is empty. Please try again.", "inoby"));
  }
  
  // Verify token with Google
  $response = wp_remote_post(
    "https://www.google.com/recaptcha/api/siteverify",
    [
      "body" => [
        "secret" => $secret_key,
        "response" => $token,
        "remoteip" => $_SERVER["REMOTE_ADDR"] ?? "",
      ],
    ],
  );
  
  if (is_wp_error($response)) {
    return new WP_Error("recaptcha_error", __("reCAPTCHA verification error. Error in reCaptcha Please try again.", "inoby"));
  }
  
  $body = json_decode(wp_remote_retrieve_body($response), true);
  
  if (!isset($body["success"]) || !$body["success"]) {
    $error_codes = $body["error-codes"] ?? [];
    return new WP_Error("recaptcha_failed", __("reCAPTCHA verification failed. Response unsuccessful Please try again.", "inoby"), $error_codes);
  }
  
  // Check score for v3 (should be >= threshold)
  if (isset($body["score"]) && $body["score"] < $score_threshold) {
    return new WP_Error("recaptcha_low_score", __("reCAPTCHA verification failed. Score is too low. Please try again.", "inoby"));
  }
  
  return true;
}

function inoby_mailchimp_subscribe($email, $lname = "", $fname = "", $merge_fields = [])
{
  $body = [
    "email_address" => $email,
    "status" => "subscribed",
  ];

  if ($fname) {
    $body["fname"] = $fname;
  }
  if ($lname) {
    $body["lname"] = $lname;
  }
  if (!empty($merge_fields)) {
    $body["merge_fields"] = $merge_fields;
  }

  return wp_remote_post(
    "https://" .
      const_or_default("MAILCHIMP_REGION", "") .
      ".api.mailchimp.com/3.0/lists/" .
      const_or_default("MAILCHIMP_LIST_ID", "") .
      "/members",
    [
      "headers" => [
        "authorization" =>
        "apikey " . const_or_default("MAILCHIMP_API_KEY", ""),
      ],
      "body" => json_encode($body),
    ],
  );
}

// Add a filter on product for set product image
add_action('restrict_manage_posts', 'filter_products_by_image_presence');
function filter_products_by_image_presence()
{
  global $typenow;
  $selected = isset($_GET['product_image_presence']) ? $_GET['product_image_presence'] : '';
  if ('product' === $typenow) {
?>
<select name="product_image_presence" id="product_image_presence">
  <option value="">Filter by product image</option>
  <option value="set" <?php selected('set', $selected); ?>>Image Set</option>
  <option value="notset" <?php selected('notset', $selected); ?>>Image Not Set</option>
</select>
<?php
  }
}

add_filter('parse_query', 'filter_products_query_by_image_presence');
function filter_products_query_by_image_presence($query)
{
  global $pagenow, $typenow;

  if ('edit.php' === $pagenow && 'product' === $typenow && isset($_GET['product_image_presence']) && $_GET['product_image_presence'] != '') {
    $presence = $_GET['product_image_presence'];
    $meta_query = array(
      'relation' => 'OR',
      array(
        'key' => '_thumbnail_id',
        'compare' => 'NOT EXISTS'
      ),
      array(
        'key' => '_thumbnail_id',
        'value' => '0'
      )
    );

    if ('set' === $presence) {
      $meta_query = array(
        array(
          'key' => '_thumbnail_id',
          'compare' => 'EXISTS'
        ),
        array(
          'key' => '_thumbnail_id',
          'value' => array('', '0'),
          'compare' => 'NOT IN'
        ),
      );
    } elseif ('notset' === $presence) {
      $meta_query = array(
        'relation' => 'OR',
        array(
          'key' => '_thumbnail_id',
          'compare' => 'NOT EXISTS'
        ),
        array(
          'key' => '_thumbnail_id',
          'value' => '0'
        )
      );
    }

    $query->set('meta_query', $meta_query);
  }
}

/**
 * Check if we are in admin for specific post type
 */
function is_post_type_admin($slug): bool {
  if(!is_admin()) {
    return false;
  }
  $post_type = $_GET["post_type"] ?? null;
  $post_id = $_GET["post"] ?? $_POST["post_ID"] ?? null;
  if ($post_type) {
    return $post_type === $slug;
  } else if ($post_id) {
    $post = get_post($post_id);
    return $post && $post->post_type === $slug;
  }
  return false;
}