<?php

namespace Fab\Helper;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * FAB Helper Template
 * - This class is used to transform the template data into FAB post type
 *
 * @package    Fab
 * @subpackage Fab/Helper
 */
class FAB_Template {

    // Load Traits.
    use \Fab\Plugin\Helper\Singleton;

    /**
     * Add new fab
     *
     * @param object $data The data.
     * @return int|WP_Error
     */
    public function add_new_fab( $data ) {
        // Read template file.
        $template = \Fab\Plugin\Helper::getInstance()->get_template( $data->id );
        $data     = \Fab\Plugin\Helper::getInstance()->ArrayMergeRecursive( $template, $data );

        // Transform template data.
        try {
            // Insert post.
            $post_id = wp_insert_post(
                array(
                    'post_type'    => 'fab',
                    'post_title'   => apply_filters( 'fab_template_title', $data->name, $data->settings->type, $data ),
                    'post_content' => $this->get_content( $data ),
                    'post_status'  => 'publish',
                )
            );

            // Add postmeta.
            $postmeta = $this->transform_template_to_postmeta( $data );
            foreach ( $postmeta as $key => $value ) {
                update_post_meta( $post_id, $key, $value );
            }

            // Add action to regenerate insight.
            do_action( 'fab_after_add_new_template', $post_id );

            return $post_id;
        } catch ( Exception $e ) {
            return new \WP_Error( 'fab_template_error', $e->getMessage() );
        }
    }

    /**
     * Get Content
     * - This function is used to get the content of the template based on the type
     *
     * @param object $data The data.
     * @return string
     */
    public function get_content( $data ) {
        $this->type = isset( $data->settings->type ) ? $data->settings->type : '';
        $content    = '';

        switch ( $data->settings->type ) {
            case 'toast' && isset( $data->settings->message ):
                $content = $data->settings->message;
                break;
            case 'modal' && isset( $data->settings->content ):
                $content = $data->settings->content;
                break;
            default:
                $content = isset( $data->settings->content ) ? $data->settings->content : '';
        }

        return apply_filters( 'fab_template_content', $content, $this->type, $data );
    }

    /**
     * FAB setting type
     * - This could be 'button', 'link', 'modal', 'toast', 'popup', etc
     *
     * @var string
     */
    private $type;

    /**
     * Get FAB setting
     *
     * @param object $data The data.
     * @param array  $postmeta The postmeta.
     * @return array
     */
    private function get_fab_setting( $data, $postmeta = array() ) {
        $postmeta['fab_template_id']  = $data->id;
        $postmeta['fab_setting_type'] = $this->type;

        // Get setting toast.
        if ( strpos( $this->type, 'toast' ) !== false ) {
            $postmeta['fab_setting_toast'] = array(
                'duration'    => isset( $data->settings->duration ) ? $data->settings->duration : '',
                'text_button' => isset( $data->settings->text_button ) ? $data->settings->text_button : '',
                'url_button'  => isset( $data->settings->url_button ) ? $data->settings->url_button : '',
                'window'      => isset( $data->settings->open_in_new_tab ) ? 1 : 0,
                'gravity'     => isset( $data->design->gravity ) ? $data->design->gravity : '',
                'position'    => isset( $data->design->position ) ? $data->design->position : '',
                'background'  => isset( $data->design->background ) ? $data->design->background : '',
                'text_color'  => isset( $data->design->text_color ) ? $data->design->text_color : '',
                'bar_color'   => isset( $data->design->bar_color ) ? $data->design->bar_color : '',
            );
        }

        return $postmeta;
    }

    /**
     * Get FAB design
     *
     * @param object $data The data.
     * @param array  $postmeta The postmeta.
     * @return array
     */
    private function get_fab_design( $data, $postmeta = array() ) {
        // Ignore icon class if type is toast.
        $ignored = array( 'toast', 'popup' );
        if ( ! in_array( $this->type, $ignored, true ) ) {
            $postmeta['fab_design_icon_class'] = isset( $data->design->icon->class ) ? $data->design->icon->class : '';
            $postmeta['fab_design_standalone'] = isset( $data->design->standalone ) ? $data->design->standalone : '';
            $postmeta['fab_design_template']   = array(
                'color'   => isset( $data->design->color ) ? $data->design->color : '',
                'icon'    => array(
                    'color' => isset( $data->design->icon->color ) ? $data->design->icon->color : '',
                ),
                'shape'   => isset( $data->design->shape ) ? $data->design->shape : '',
                'grouped' => isset( $data->design->grouped ) ? $data->design->grouped : '',
            );
        }

        return $postmeta;
    }

    /**
     * Get FAB modal
     *
     * @param object $data The data.
     * @param array  $postmeta The postmeta.
     * @return array
     */
    private function get_fab_modal( $data, $postmeta = array() ) {
        $allowed = array( 'modal', 'related_post', 'auth_login', 'auth_logout', 'search' );
        if ( in_array( $this->type, $allowed, true ) ) {
            // Set size type.
            if ( isset( $data->modal->size ) ) {
                $postmeta['fab_design_size_type'] = $data->modal->size;
            }

            // Set layout.
            if ( isset( $data->modal->layout ) ) {
                $postmeta['fab_modal_layout'] = $data->modal->layout;
            }

            // Set navigation.
            if ( isset( $data->modal->navigation ) ) {
                $postmeta['fab_modal_navigation'] = (object) array_map(
                    array( \Fab\Plugin\Helper::getInstance(), 'transformBooleanValue' ),
                    (array) $data->modal->navigation
                );
            }
        }

        return $postmeta;
    }

    /**
     * Get FAB responsive
     *
     * @param object $data The data.
     * @param array  $postmeta The postmeta.
     * @return array
     */
    private function get_fab_responsive( $data, $postmeta = array() ) {
        // Set to 0 if not set, create variable for each device.
        $mobile  = isset( $data->design->responsive->device->mobile ) ? $data->design->responsive->device->mobile : 0;
        $tablet  = isset( $data->design->responsive->device->tablet ) ? $data->design->responsive->device->tablet : 0;
        $desktop = isset( $data->design->responsive->device->desktop ) ? $data->design->responsive->device->desktop : 0;

        // Standaardize the boolean value.
        $mobile  = \Fab\Plugin\Helper::getInstance()->transformBooleanValue( $mobile );
        $tablet  = \Fab\Plugin\Helper::getInstance()->transformBooleanValue( $tablet );
        $desktop = \Fab\Plugin\Helper::getInstance()->transformBooleanValue( $desktop );

        // Set the postmeta.
        $postmeta['fab_design_responsive'] = array(
            'device' => array(
                'mobile'  => $mobile,
                'tablet'  => $tablet,
                'desktop' => $desktop,
            ),
        );

        return $postmeta;
    }

    /**
     * Get FAB trigger & cookies
     *
     * @param object $data The data.
     * @param array  $postmeta The postmeta.
     * @return array
     */
    private function get_fab_trigger( $data, $postmeta = array() ) {
        // Only for popup, toast & modal.
        $allowed = array( 'popup', 'toast', 'modal' );
        if ( in_array( $this->type, $allowed, true ) ) {
            $postmeta['fab_trigger'] = array(
                'type'   => isset( $data->trigger->type ) ? $data->trigger->type : '',
                'delay'  => isset( $data->trigger->delay ) ? $data->trigger->delay : '',
                'cookie' => array(
                    'expiration' => isset( $data->cookie->expiration ) ? $data->cookie->expiration : 0,
                ),
            );
        }

        return $postmeta;
    }

    /**
     * Transform template data
     *
     * @param object $data The data.
     * @return array
     */
    public function transform_template_to_postmeta( object $data ) {
        $this->type = isset( $data->settings->type ) ? $data->settings->type : '';

        // Transform template data.
        $postmeta = array();
        $postmeta = $this->get_fab_setting( $data, $postmeta );
        $postmeta = $this->get_fab_design( $data, $postmeta );
        $postmeta = $this->get_fab_modal( $data, $postmeta );
        $postmeta = $this->get_fab_responsive( $data, $postmeta );
        $postmeta = $this->get_fab_trigger( $data, $postmeta );

        return apply_filters( 'fab_template_postmeta', $postmeta, $this->type, $data );
    }

    /**
     * Export template data from a FAB post
     *
     * @param int $post_id The post ID.
     * @return object|WP_Error The template data or WP_Error if not found.
     */
    public function export_template_from_post( $post_id ) {
        // Get post data.
        $post = get_post( $post_id );
        if ( ! $post ) {
            return new \WP_Error( 'fab_post_error', __( 'Post not found', 'floating-awesome-button' ) );
        }

        // Get template ID from post meta.
        $template_id = get_post_meta( $post_id, 'fab_template_id', true );

        // Create template ID from post title.
        $post_title_id = strtolower( trim( $post->post_title ) );
        $post_title_id = preg_replace( '/[^a-z0-9\s-]/', '', $post_title_id ); // Remove special characters.
        $post_title_id = preg_replace( '/\s+/', '-', $post_title_id ); // Replace spaces with dashes.
        $post_title_id = preg_replace( '/-+/', '-', $post_title_id ); // Replace multiple dashes with single dash.
        $post_title_id = trim( $post_title_id, '-' ); // Remove leading/trailing dashes.

        // Fallback if title is empty or becomes empty after cleaning.
        if ( empty( $post_title_id ) ) {
            $post_title_id = 'fab-post-' . $post_id;
        }

        // Initialize template object - start with base template if available.
        if ( ! empty( $template_id ) ) {
            $template = \Fab\Plugin\Helper::getInstance()->get_template( $template_id );
            if ( is_wp_error( $template ) ) {
                // If base template not found, create empty template.
                $template     = new \stdClass();
                $template->id = $post_title_id;
            } else {
                // Update ID to use post title format.
                $template->id = $post_title_id;
            }
        } else {
            // Create empty template object.
            $template     = new \stdClass();
            $template->id = $post_title_id;
        }

        // Initialize main properties if they don't exist.
        if ( ! isset( $template->name ) ) {
            $template->name = '';
        }
        if ( ! isset( $template->description ) ) {
            $template->description = '';
        }
        if ( ! isset( $template->license ) ) {
            $template->license = 'free';
        }
        if ( ! isset( $template->settings ) ) {
            $template->settings = new \stdClass();
        }
        if ( ! isset( $template->design ) ) {
            $template->design = new \stdClass();
        }

        // Update template with post data.
        $template->name = $post->post_title;

        // Get all post meta.
        $post_metas = get_post_meta( $post_id );

        // Update settings based on post meta.
        if ( isset( $post_metas['fab_setting_type'] ) ) {
            $template->settings->type = $post_metas['fab_setting_type'][0];
        }

        // Add link if exists.
        if ( isset( $post_metas['fab_setting_link'] ) ) {
            $template->settings->link = $post_metas['fab_setting_link'][0];
        }

        // Add link behavior (open_in_new_tab).
        if ( isset( $post_metas['fab_setting_link_behavior'] ) ) {
            $link_behavior                       = $post_metas['fab_setting_link_behavior'][0];
            $template->settings->open_in_new_tab = ( 'yes' === $link_behavior || '1' === $link_behavior || 1 === $link_behavior ) ? true : false;
        }

        // Add content from post content.
        if ( $post->post_content ) {
            // For toast type, use message instead of content.
            if ( isset( $template->settings->type ) && ( 'toast' === $template->settings->type || strpos( $template->settings->type, 'toast' ) !== false ) ) {
                $template->settings->message = $post->post_content;
            } else {
            $template->settings->content = $post->post_content;
            }
        }

        // Add toast settings if exists.
        if ( isset( $post_metas['fab_setting_toast'] ) ) {
            $toast = maybe_unserialize( $post_metas['fab_setting_toast'][0] );
            if ( is_array( $toast ) ) {
                $template->settings->duration    = isset( $toast['duration'] ) ? intval( $toast['duration'] ) : '';
                $template->settings->text_button = isset( $toast['text_button'] ) ? $toast['text_button'] : '';
                $template->settings->url_button  = isset( $toast['url_button'] ) ? $toast['url_button'] : '';

                // Only set open_in_new_tab if not already set from link_behavior.
                if ( ! isset( $template->settings->open_in_new_tab ) ) {
                $template->settings->open_in_new_tab = isset( $toast['window'] ) && $toast['window'] ? true : false;
                }

                // Add toast design properties.
                if ( ! isset( $template->design ) ) {
                    $template->design = new \stdClass();
                }
                $template->design->gravity    = isset( $toast['gravity'] ) ? $toast['gravity'] : '';
                $template->design->position   = isset( $toast['position'] ) ? $toast['position'] : '';
                $template->design->background = isset( $toast['background'] ) ? $toast['background'] : '';
                $template->design->text_color = isset( $toast['text_color'] ) ? $toast['text_color'] : '';
                $template->design->bar_color  = isset( $toast['bar_color'] ) ? $toast['bar_color'] : '';
            }
        }

        // Add design template if exists.
        if ( isset( $post_metas['fab_design_template'] ) ) {
            $design = maybe_unserialize( $post_metas['fab_design_template'][0] );
            if ( is_array( $design ) ) {
                if ( ! isset( $template->design ) ) {
                    $template->design = new \stdClass();
                }
                $template->design->color   = isset( $design['color'] ) ? $design['color'] : '';
                $template->design->shape   = isset( $design['shape'] ) ? $design['shape'] : '';
                $template->design->grouped = isset( $design['grouped'] ) ? (bool) $design['grouped'] : true;

                // Add icon properties.
                if ( ! isset( $template->design->icon ) ) {
                    $template->design->icon = new \stdClass();
                }
                if ( isset( $design['icon']['color'] ) ) {
                    $template->design->icon->color = $design['icon']['color'];
                }
            }
        }

        // Add icon class if exists.
        if ( isset( $post_metas['fab_design_icon_class'] ) ) {
            if ( ! isset( $template->design ) ) {
                $template->design = new \stdClass();
            }
            if ( ! isset( $template->design->icon ) ) {
                $template->design->icon = new \stdClass();
            }
            $template->design->icon->class = $post_metas['fab_design_icon_class'][0];
        }

        // Add standalone property if exists.
        if ( isset( $post_metas['fab_design_standalone'] ) ) {
            if ( ! isset( $template->design ) ) {
                $template->design = new \stdClass();
            }
            $template->design->standalone = (bool) $post_metas['fab_design_standalone'][0];
        }

        // Add responsive settings if exists.
        if ( isset( $post_metas['fab_design_responsive'] ) ) {
            $responsive = maybe_unserialize( $post_metas['fab_design_responsive'][0] );
            if ( is_array( $responsive ) && isset( $responsive['device'] ) ) {
                if ( ! isset( $template->design ) ) {
                    $template->design = new \stdClass();
                }
                $template->design->responsive                  = new \stdClass();
                $template->design->responsive->device          = new \stdClass();
                $template->design->responsive->device->mobile  = isset( $responsive['device']['mobile'] ) ? (int) $responsive['device']['mobile'] : 1;
                $template->design->responsive->device->tablet  = isset( $responsive['device']['tablet'] ) ? (int) $responsive['device']['tablet'] : 1;
                $template->design->responsive->device->desktop = isset( $responsive['device']['desktop'] ) ? (int) $responsive['device']['desktop'] : 1;
            }
        }

        // Add modal settings if exists.
        if ( isset( $post_metas['fab_modal_layout'] ) ) {
            $layout = maybe_unserialize( $post_metas['fab_modal_layout'][0] );
            if ( is_array( $layout ) ) {
                if ( ! isset( $template->modal ) ) {
                    $template->modal = new \stdClass();
                }
                $template->modal->layout = $layout;
            }
        }

        if ( isset( $post_metas['fab_modal_navigation'] ) ) {
            $navigation = maybe_unserialize( $post_metas['fab_modal_navigation'][0] );
            if ( is_array( $navigation ) || is_object( $navigation ) ) {
                if ( ! isset( $template->modal ) ) {
                    $template->modal = new \stdClass();
                }
                $template->modal->navigation = $navigation;
            }
        }

        // Add trigger settings if exists.
        if ( isset( $post_metas['fab_trigger'] ) ) {
            $trigger = maybe_unserialize( $post_metas['fab_trigger'][0] );
            if ( is_array( $trigger ) ) {
                $trigger_type  = isset( $trigger['type'] ) ? $trigger['type'] : '';
                $trigger_delay = isset( $trigger['delay'] ) ? $trigger['delay'] : '';

                // Only add trigger if type or delay is not empty.
                if ( ! empty( $trigger_type ) || ! empty( $trigger_delay ) ) {
                    $template->trigger        = new \stdClass();
                    $template->trigger->type  = $trigger_type;
                    $template->trigger->delay = $trigger_delay;
                }

                // Add cookie settings if exist.
                if ( isset( $trigger['cookie'] ) && is_array( $trigger['cookie'] ) ) {
                    $template->cookie             = new \stdClass();
                    $template->cookie->expiration = isset( $trigger['cookie']['expiration'] ) ? $trigger['cookie']['expiration'] : '0';
                }
            }
        }

        // Add modal size if exists.
        if ( isset( $post_metas['fab_design_size_type'] ) ) {
            if ( ! isset( $template->modal ) ) {
                $template->modal = new \stdClass();
            }
            $template->modal->size = $post_metas['fab_design_size_type'][0];
        }

        // Add description if not set.
        if ( empty( $template->description ) && $post->post_content ) {
            $template->description = wp_trim_words( $post->post_content, 20 );
        }

        // Add location settings if exists.
        if ( isset( $post_metas['fab_location'] ) ) {
            $raw_location = $post_metas['fab_location'][0];
            $location     = null;

            // Try multiple decode methods as location can be stored differently.
            if ( ! empty( $raw_location ) ) {
                // First try unserialize (WordPress standard).
                $location = maybe_unserialize( $raw_location );

                // If that fails, try JSON decode (as seen in FABMetaboxLocation).
                if ( ! is_array( $location ) || empty( $location ) ) {
                    $location = json_decode( $raw_location, true );
                }

                // If still no valid data, try WordPress safe unserialize.
                if ( ! is_array( $location ) && is_string( $raw_location ) ) {
                    // Use WordPress maybe_unserialize again but with different checks.
                    if ( is_serialized( $raw_location ) ) {
                        $location = maybe_unserialize( $raw_location );
                    }
                }
            }

            // Add to template if we have valid location data.
            if ( is_array( $location ) && ! empty( $location ) ) {
                // Clean up location data format to ensure logic is string, not array.
                $cleaned_location   = $this->clean_location_format( $location );
                $template->location = $cleaned_location;
            }
        }

        // Add requires if exists.
        if ( isset( $post_metas['fab_requires'] ) ) {
            $requires = maybe_unserialize( $post_metas['fab_requires'][0] );
            if ( is_array( $requires ) && ! empty( $requires ) ) {
                $template->requires = $requires;
            }
        }

        // Add toast-specific design properties that are stored separately.
        if ( isset( $post_metas['fab_setting_toast'] ) ) {
            $toast = maybe_unserialize( $post_metas['fab_setting_toast'][0] );
            if ( is_array( $toast ) ) {
                // Add closeable property.
                if ( isset( $toast['closeable'] ) ) {
                    $template->design->closeable = (bool) $toast['closeable'];
                }
            }
        }

        // Handle design properties that might be stored as separate meta.
        if ( isset( $post_metas['fab_design_closeable'] ) ) {
            $template->design->closeable = (bool) $post_metas['fab_design_closeable'][0];
        }

        return $template;
    }

    /**
     * Clean location format to ensure proper structure
     *
     * @param array $location The location data.
     * @return array Cleaned location data.
     */
    private function clean_location_format( $location ) {
        if ( ! is_array( $location ) ) {
            return $location;
        }

        $cleaned = array();
        foreach ( $location as $group ) {
            if ( ! is_array( $group ) || ! isset( $group['rules'] ) ) {
                continue;
            }

            $cleaned_group = array(
                'logic' => isset( $group['logic'] ) ? $group['logic'] : null,
                'rules' => array(),
            );

            foreach ( $group['rules'] as $rule ) {
                if ( ! is_array( $rule ) ) {
                    continue;
                }

                $cleaned_rule = array(
                    'type'     => isset( $rule['type'] ) ? $rule['type'] : '',
                    'operator' => isset( $rule['operator'] ) ? $rule['operator'] : '',
                    'value'    => isset( $rule['value'] ) ? $rule['value'] : '',
                    'logic'    => isset( $rule['logic'] ) ? $this->normalize_logic_value( $rule['logic'] ) : 'OR',
                );

                $cleaned_group['rules'][] = $cleaned_rule;
            }

            $cleaned[] = $cleaned_group;
        }

        return $cleaned;
    }

    /**
     * Normalize logic value to ensure it's a string
     *
     * @param mixed $logic The logic value.
     * @return string Normalized logic value.
     */
    private function normalize_logic_value( $logic ) {
        // If it's already a string, return as is.
        if ( is_string( $logic ) ) {
            return $logic;
        }

        // If it's an array, get the first value.
        if ( is_array( $logic ) && ! empty( $logic ) ) {
            return (string) $logic[0];
        }

        // Default fallback.
        return 'OR';
    }

    /**
     * Transform template data to be displayed in metabox.
     *
     * @param array  $templates The templates.
     * @param array  $with_id The id.
     * @param string $with_id_key The id key.
     * @return array
     */
    public function transform_metabox_templates( $templates, $with_id = array(), $with_id_key = '' ) {
        global $post;

        foreach ( $templates as &$template ) {
            $template = \Fab\Plugin\Helper::getInstance()->get_template( $template );

            // If $template is not an object, early return.
            if ( ! is_object( $template ) ) {
                continue;
            }

            // Check if all required plugins are active.
            if ( isset( $template->requires ) && ! \Fab\Plugin\Helper::getInstance()->isArrayInArray( $template->requires, get_option( 'active_plugins' ) ) ) {
                continue;
            }

            // Transform template.
            $template = array(
                'id'          => $template->id,
                'name'        => $template->name,
                'description' => $template->description,
                'license'     => $template->license,
                'requires'    => $template->requires ?? array(),
                'docs'        => isset( $template->docs ) ? $template->docs : '',
                'design'      => array(
                    'color' => $template->design->color,
                    'icon'  => array(
                        'color' => $template->design->icon->color,
                        'class' => $template->design->icon->class,
                    ),
                ),
            );

            // Add with_id attribute to template.
            if ( $with_id_key && in_array( $template['id'], $with_id, true ) ) {
                $template[ $with_id_key ] = $post->ID;
            }
        }

        return $templates;
    }
}
