<?php

namespace WDevs\CustomerOrderExport;

use WDevs\CustomerOrderExport\Channels\CustomerAccountChannel;
use WDevs\CustomerOrderExport\Channels\EmailChannel;
use WDevs\CustomerOrderExport\Channels\GoogleDriveChannel;
use WDevs\CustomerOrderExport\Channels\OrderChannel;
class Template {
    /**
     * Template ID.
     *
     * @var int|null
     */
    protected $id = null;

    /**
     * Template name.
     *
     * @var string|null
     */
    protected $name = null;

    /**
     * Template columns.
     *
     * @var array
     */
    protected $columns = [];

    /**
     * Constructor.
     *
     * @param int|object|null $template Template ID, template object, or null for new template
     */
    public function __construct( $template = null ) {
        if ( is_numeric( $template ) && !empty( $template ) ) {
            $this->set_id( $template );
        } elseif ( is_object( $template ) ) {
            $this->set_id( $template->id ?? 0 );
        } else {
            $this->set_id( 0 );
        }
        $this->initialize();
    }

    /**
     * Get the requested template ID from GET parameters.
     *
     * @return int|null Returns template ID or null if invalid
     * @since 1.0.0
     */
    public static function get_requested_template_id() {
        $template_id = ( isset( $_GET['template_id'] ) ? sanitize_text_field( wp_unslash( $_GET['template_id'] ) ) : '' );
        if ( $template_id === 'new' ) {
            return 0;
        }
        $template_id = absint( $template_id );
        return ( $template_id ?: null );
    }

    /**
     * Get default template name.
     *
     * @return string
     * @since 1.0.0
     */
    public static function get_default_name() {
        return __( 'Template', 'orderbridge-for-woocommerce' );
    }

    /* --------------------------------------------------------------------------
     * Getters
     * ---------------------------------------------------------------------- */
    /**
     * Get template ID.
     *
     * @return int|null
     * @since 1.0.0
     */
    public function get_id() {
        return $this->id;
    }

    /**
     * Get template name.
     *
     * @return string|null
     * @since 1.0.0
     */
    public function get_name() {
        return $this->name;
    }

    /**
     * Get template columns.
     *
     * @return array
     */
    public function get_columns() {
        return ( $this->id !== null ? $this->columns : [] );
    }

    /**
     * Get template columns.
     *
     * @return array
     * @since 1.0.0
     */
    public function get_selectable_columns() : array {
        $allowed_columns = Column::get_allowed_columns();
        $columns_data = $this->get_columns();
        $used_columns = [];
        foreach ( $columns_data as $category => $items ) {
            if ( is_array( $items ) ) {
                $used_columns = array_merge( $used_columns, array_column( $items, 'id' ) );
            }
        }
        // Loop through each category and mark fields as selectable
        foreach ( $allowed_columns as $category => &$category_data ) {
            foreach ( $category_data['fields'] as $field_key => &$field_data ) {
                $field_data['selectable'] = !in_array( $field_key, $used_columns, true );
            }
            // Sort fields alphabetically within each category
            uasort( $category_data['fields'], function ( $a, $b ) {
                return strcmp( $a['field'], $b['field'] );
            } );
        }
        $selectable_columns = array_filter( $allowed_columns, function ( $category_data ) {
            return !empty( $category_data['fields'] );
        } );
        return apply_filters( 'wdevs_coe_get_selectable_columns', $selectable_columns );
    }

    /**
     * Retrieves the selected columns with their custom names if set.
     *
     * @return array An array of selected columns grouped by categories with their IDs and custom names
     * @since 1.0.0
     */
    public function get_selected_columns() {
        $saved_columns = $this->get_columns();
        $allowed_columns = Column::get_allowed_columns();
        $selected_columns = [];
        foreach ( $allowed_columns as $category => $category_data ) {
            $selected_columns[$category] = [
                'name'   => $category_data['name'],
                'fields' => [],
            ];
        }
        foreach ( $saved_columns as $category_columns ) {
            foreach ( $category_columns as $column ) {
                $column_id = $column['id'] ?? '';
                foreach ( $allowed_columns as $category => $category_data ) {
                    if ( isset( $category_data['fields'][$column_id] ) ) {
                        $selected_columns[$category]['fields'][$column_id] = [
                            'field'       => $category_data['fields'][$column_id]['field'],
                            'name'        => $column['name'] ?? $category_data['fields'][$column_id]['name'],
                            'order'       => $column['order'] ?? 0,
                            'description' => $category_data['fields'][$column_id]['description'] ?? '',
                        ];
                        break;
                    }
                }
            }
        }
        return apply_filters( 'wdevs_coe_get_selected_columns', $selected_columns );
    }

    /**
     * Flattens and sorts the selected columns structure
     *
     * @return array Flattened array of selected columns with category references
     * @since 1.0.0
     */
    public function get_selected_columns_flattened() {
        $selected_columns = $this->get_selected_columns();
        $flattened_selected_columns = [];
        foreach ( $selected_columns as $category_id => $category_data ) {
            if ( !empty( $category_data['fields'] ) ) {
                foreach ( $category_data['fields'] as $field_id => $field_data ) {
                    $field_data['category_id'] = $category_id;
                    $flattened_selected_columns[$field_id] = $field_data;
                }
            }
        }
        uasort( $flattened_selected_columns, function ( $a, $b ) {
            return $a['order'] <=> $b['order'];
        } );
        return $flattened_selected_columns;
    }

    /* --------------------------------------------------------------------------
     * Setters
     * ---------------------------------------------------------------------- */
    /**
     * Set template ID.
     *
     * @param int $id
     *
     * @return void
     * @since 1.0.0
     */
    public function set_id( int $id ) {
        $this->id = absint( $id );
    }

    /**
     * Set template name.
     *
     * @param string $name
     *
     * @return void
     * @since 1.0.0
     */
    public function set_name( string $name ) {
        $this->name = wc_clean( $name );
    }

    /**
     * Set template columns.
     *
     * @param array $columns Array of columns data
     *
     * @return void
     * @since 1.0.0
     */
    public function set_columns( array $columns ) {
        $allowed_columns = Column::get_allowed_columns();
        $existing_columns = $this->get_columns();
        $updated_columns = $existing_columns;
        $selected_columns_flattened = $this->get_selected_columns_flattened();
        $number_of_selected_columns = count( $selected_columns_flattened );
        $new_order = $number_of_selected_columns + 1;
        foreach ( $columns as $column_id => $column_data ) {
            if ( empty( $column_data['category_id'] ) ) {
                continue;
            }
            $category_id = sanitize_text_field( $column_data['category_id'] );
            if ( !array_key_exists( $category_id, $allowed_columns ) ) {
                continue;
            }
            if ( empty( $column_id ) ) {
                continue;
            }
            $column_id = sanitize_text_field( $column_id );
            if ( !array_key_exists( $column_id, $allowed_columns[$category_id]['fields'] ) ) {
                continue;
            }
            if ( isset( $column_data['deleted'] ) ) {
                if ( array_key_exists( $category_id, $updated_columns ) ) {
                    $updated_columns[$category_id] = array_filter( $updated_columns[$category_id], function ( $column ) use($column_id) {
                        return $column['id'] !== $column_id;
                    } );
                }
                continue;
            }
            $existing_index = null;
            if ( array_key_exists( $category_id, $updated_columns ) ) {
                foreach ( $updated_columns[$category_id] as $index => $column ) {
                    if ( $column['id'] === $column_id ) {
                        $existing_index = $index;
                        break;
                    }
                }
            }
            if ( empty( $column_data['name'] ) ) {
                //new column: name is required
                if ( $existing_index === null ) {
                    continue;
                }
                //editing: if name AND order are empty, continue
                if ( !isset( $column_data['order'] ) ) {
                    continue;
                }
            }
            $name = ( isset( $column_data['name'] ) ? sanitize_text_field( $column_data['name'] ) : null );
            if ( $existing_index !== null ) {
                if ( isset( $column_data['name'] ) && !empty( $column_data['name'] ) ) {
                    $updated_columns[$category_id][$existing_index]['name'] = $name;
                }
                if ( isset( $column_data['order'] ) ) {
                    $updated_columns[$category_id][$existing_index]['order'] = absint( $column_data['order'] );
                }
            } else {
                $updated_columns[$category_id][] = [
                    'id'    => $column_id,
                    'name'  => $name,
                    'order' => $new_order,
                ];
                $new_order++;
            }
        }
        uasort( $updated_columns, function ( $a, $b ) {
            return $a['order'] <=> $b['order'];
        } );
        $this->columns = $updated_columns;
    }

    /* --------------------------------------------------------------------------
     * CRUD Operations
     * ---------------------------------------------------------------------- */
    /**
     * Save template to database.
     *
     * @return int|null Saved template ID or null on failure
     * @since 1.0.0
     */
    public function save() {
        if ( empty( $this->name ) ) {
            $this->set_name( self::get_default_name() );
        }
        $templates = self::get_templates();
        if ( $this->id > 0 ) {
            // Update existing template
            $templates[$this->id] = $this->to_array();
        } else {
            // Create new template - generate new ID
            $this->id = $this->generate_new_id( $templates );
            $templates[$this->id] = $this->to_array();
        }
        update_option( 'wdevs_coe_templates', $templates );
        return $this->id;
    }

    /**
     * Delete the current template.
     *
     * @return bool True if deleted successfully, false otherwise
     * @since 1.0.0
     */
    public function delete() {
        if ( $this->id === null || $this->id <= 0 ) {
            return false;
        }
        $templates = self::get_templates();
        if ( !isset( $templates[$this->id] ) ) {
            return false;
        }
        unset($templates[$this->id]);
        $option_keys = [EmailChannel::$template_option_key, OrderChannel::$template_option_key];
        foreach ( $option_keys as $option_key ) {
            $option_value = get_option( $option_key );
            if ( (int) $option_value === (int) $this->id ) {
                delete_option( $option_key );
            }
        }
        return update_option( 'wdevs_coe_templates', $templates );
    }

    /* --------------------------------------------------------------------------
     * Internal Methods
     * ---------------------------------------------------------------------- */
    /**
     * Initialize template data.
     * @since 1.0.0
     */
    protected function initialize() {
        if ( $this->id === null ) {
            return;
        }
        $template = $this->get_template();
        if ( $template ) {
            $this->name = $template['name'] ?? null;
            $this->columns = $template['columns'] ?? [];
        }
    }

    /**
     * Get template data from storage.
     *
     * @return array|null
     * @since 1.0.0
     */
    protected function get_template() {
        if ( $this->id === null || $this->id <= 0 ) {
            return null;
        }
        $templates = self::get_templates();
        return $templates[$this->id] ?? null;
    }

    /**
     * Convert template to array.
     *
     * @return array
     * @since 1.0.0
     */
    protected function to_array() {
        return [
            'name'    => $this->name,
            'columns' => $this->columns,
        ];
    }

    /**
     * Generate a new unique template ID.
     *
     * @param array $existing_templates
     *
     * @return int
     * @since 1.0.0
     */
    protected function generate_new_id( array $existing_templates ) {
        return ( !empty( $existing_templates ) ? max( array_keys( $existing_templates ) ) + 1 : 1 );
    }

    /**
     * Get all templates from options.
     *
     * @return array
     * @since 1.0.0
     */
    protected static function get_templates() {
        return get_option( 'wdevs_coe_templates', [] );
    }

}
