<?php

/**
 * Leads list table (extends core WP_List_Table).
 *
 * @package Leadite
 */
namespace Leadite\Admin;

use Leadite\Config;
use Leadite\Pro;
use Leadite\Storage\LeadsRepository;
use Leadite\Support\FieldMapper;
defined( 'ABSPATH' ) || exit;
if ( !class_exists( '\\WP_List_Table' ) ) {
    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}
class LeadsListTable extends \WP_List_Table {
    /** @var int */
    protected $total = 0;

    /**
     * Pre-fetched meta map: [submission_id => ['row' => object, 'fields' => object[]]].
     * Populated in prepare_items() via find_many() to eliminate N+1 queries.
     *
     * @var array
     */
    protected $meta_map = array();

    /**
     * Pre-fetched tags map: [submission_id => object[]].
     *
     * @var array
     */
    protected $tags_map = array();

    public function __construct() {
        parent::__construct( array(
            'singular' => 'lead',
            'plural'   => 'leads',
            'ajax'     => false,
        ) );
    }

    /**
     * Column definitions.
     *
     * @return array
     */
    public function get_columns() {
        $cols = array(
            'cb' => '<input type="checkbox" />',
        );
        // f-pro-end
        $cols['lead'] = __( 'Lead', 'leadite' );
        $cols['source'] = __( 'Source', 'leadite' );
        $cols['form_name'] = __( 'Form', 'leadite' );
        $cols['status'] = __( 'Status', 'leadite' );
        // f-pro-end
        $cols['created_at'] = __( 'Date', 'leadite' );
        return $cols;
    }

    /**
     * Hidden columns — always return an array to avoid the PHP 8.x TypeError
     * thrown by in_array() when get_user_option() returns false (i.e. the user
     * has never customised column visibility for this screen).
     *
     * @return array
     */
    public function get_hidden_columns() {
        $hidden = parent::get_hidden_columns();
        return ( is_array( $hidden ) ? $hidden : array() );
    }

    /**
     * Sortable columns.
     *
     * @return array
     */
    protected function get_sortable_columns() {
        return array(
            'created_at' => array('created_at', true),
            'status'     => array('status', false),
            'source'     => array('source', false),
            'form_name'  => array('form_name', false),
        );
    }

    /**
     * Bulk actions.
     *
     * @return array
     */
    protected function get_bulk_actions() {
        return array(
            'mark_read'   => __( 'Mark as read', 'leadite' ),
            'mark_closed' => __( 'Mark as closed', 'leadite' ),
            'mark_spam'   => __( 'Mark as spam', 'leadite' ),
            'export_csv'  => __( 'Export selected — CSV', 'leadite' ),
            'export_xlsx' => __( 'Export selected — XLSX', 'leadite' ),
            'export_json' => __( 'Export selected — JSON', 'leadite' ),
            'delete'      => __( 'Delete', 'leadite' ),
        );
    }

    /**
     * Checkbox column.
     *
     * @param object $item Row.
     * @return string
     */
    public function column_cb( $item ) {
        return sprintf( '<input type="checkbox" name="ids[]" value="%d" />', (int) $item->id );
    }

    /**
     * Star column — inline AJAX toggle button.
     *
     * @param object $item Row.
     * @return string
     */
    public function column_starred( $item ) {
        $is_starred = !empty( $item->starred );
        $nonce = wp_create_nonce( 'leadite_starred_' . (int) $item->id );
        return sprintf(
            '<button type="button" class="leadite-star-btn leadite-star-btn--list %s" data-lead-id="%d" data-nonce="%s" aria-label="%s" title="%s">%s</button>',
            ( $is_starred ? 'is-starred' : '' ),
            (int) $item->id,
            esc_attr( $nonce ),
            ( $is_starred ? esc_attr__( 'Remove from favourites', 'leadite' ) : esc_attr__( 'Add to favourites', 'leadite' ) ),
            ( $is_starred ? esc_attr__( 'Starred', 'leadite' ) : esc_attr__( 'Star this lead', 'leadite' ) ),
            ( $is_starred ? '…' : '→' )
        );
    }

    /**
     * The primary "Lead" column: pulls canonical name/email/phone for a clean preview.
     *
     * @param object $item Row.
     * @return string
     */
    public function column_lead( $item ) {
        // Use the pre-fetched meta_map populated in prepare_items().
        // Fall back to a live find() only if an item somehow arrived outside the
        // normal prepare_items() flow (e.g. programmatic table rendering).
        if ( isset( $this->meta_map[(int) $item->id] ) ) {
            $entry = $this->meta_map[(int) $item->id];
            $fields = $entry['fields'];
        } else {
            $data = LeadsRepository::find( $item->id );
            $fields = $data['fields'];
        }
        $name = FieldMapper::canonical_value( $fields, 'full_name' );
        $email = FieldMapper::canonical_value( $fields, 'email' );
        $phone = FieldMapper::canonical_value( $fields, 'phone' );
        $title = ( $name ? $name : (( $email ? $email : __( '(no name)', 'leadite' ) )) );
        $view_url = add_query_arg( array(
            'page' => 'leadite-leads',
            'view' => (int) $item->id,
        ), admin_url( 'admin.php' ) );
        $is_imported = false;
        foreach ( $fields as $f ) {
            $f_key = ( is_array( $f ) ? $f['key'] ?? '' : $f->field_key ?? '' );
            $f_val = ( is_array( $f ) ? $f['value'] ?? '' : $f->field_value ?? '' );
            if ( '_imported' === $f_key && '1' === $f_val ) {
                $is_imported = true;
                break;
            }
        }
        $html = '<div class="leadite-row-primary-cell">';
        $html .= '<div class="leadite-row-title-wrap"><strong><a class="row-title" href="' . esc_url( $view_url ) . '">' . esc_html( $title ) . '</a></strong>';
        if ( $is_imported ) {
            $html .= ' <span class="leadite-badge leadite-badge--imported" style="background:#d97706; color:#fff; font-size:10px; font-weight:normal; margin-inline-start:6px; padding:2px 6px;">' . esc_html__( 'Imported', 'leadite' ) . '</span>';
        }
        $html .= '</div>';
        if ( $email ) {
            $html .= '<div class="leadite-row-meta-line"><span class="leadite-list__sub">' . esc_html( $email ) . '</span></div>';
        }
        if ( $phone ) {
            $html .= '<div class="leadite-row-meta-line"><span class="leadite-list__sub">' . esc_html( $phone ) . '</span></div>';
        }
        if ( !empty( $item->page_url ) ) {
            $page_label = self::get_page_label( $item->page_url );
            $html .= '<div class="leadite-row-meta-line"><span class="leadite-list__sub">' . esc_html__( 'Page:', 'leadite' ) . ' <a href="' . esc_url( $item->page_url ) . '" target="_blank">' . esc_html( $page_label ) . '</a></span></div>';
        }
        $html .= '</div>';
        $row_actions = array(
            'view' => '<a href="' . esc_url( $view_url ) . '">' . esc_html__( 'View', 'leadite' ) . '</a>',
        );
        return $html . $this->row_actions( $row_actions );
    }

    /**
     * Source badge.
     *
     * @param object $item Row.
     * @return string
     */
    public function column_source( $item ) {
        return '<span class="leadite-badge leadite-badge--source">' . esc_html( $item->source ) . '</span>';
    }

    public function column_form_name( $item ) {
        return esc_html( ( $item->form_name ? $item->form_name : '—' ) );
    }

    /**
     * Status badge.
     *
     * @param object $item Row.
     * @return string
     */
    public function column_status( $item ) {
        $labels = array(
            'new'         => __( 'New', 'leadite' ),
            'read'        => __( 'Read', 'leadite' ),
            'in_progress' => __( 'In progress', 'leadite' ),
            'closed'      => __( 'Closed', 'leadite' ),
            'spam'        => __( 'Spam', 'leadite' ),
        );
        $label = ( isset( $labels[$item->status] ) ? $labels[$item->status] : $item->status );
        return '<span class="leadite-badge leadite-badge--status leadite-badge--' . esc_attr( $item->status ) . '">' . esc_html( $label ) . '</span>';
    }

    /**
     * Follow-Up Guard priority column (Pro only).
     * Shows a compact hot/warm/cold badge from the cached hot_score and
     * an SLA icon if the lead is needs_attention or overdue.
     *
     * @param object $item Row.
     * @return string
     */
    public function column_followup( $item ) {
        $score = ( isset( $item->hot_score_cached ) ? (int) $item->hot_score_cached : 0 );
        $sla_status = ( isset( $item->sla_status ) ? (string) $item->sla_status : '' );
        $threshold = (int) \Leadite\Config::get( 'followup_hot_threshold', 50 );
        // Compact inline SVG icons.
        $allowed_html = array(
            'svg'      => array(
                'width'           => true,
                'height'          => true,
                'viewbox'         => true,
                'fill'            => true,
                'stroke'          => true,
                'stroke-width'    => true,
                'stroke-linecap'  => true,
                'stroke-linejoin' => true,
                'aria-hidden'     => true,
            ),
            'path'     => array(
                'd' => true,
            ),
            'circle'   => array(
                'cx' => true,
                'cy' => true,
                'r'  => true,
            ),
            'line'     => array(
                'x1' => true,
                'y1' => true,
                'x2' => true,
                'y2' => true,
            ),
            'polyline' => array(
                'points' => true,
            ),
        );
        $svg_hot = wp_kses( '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>', $allowed_html );
        $svg_warn = wp_kses( '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m10.29 3.86-8.29 14.34A1 1 0 0 0 2.83 20h18.34a1 1 0 0 0 .83-1.5L13.71 4.14a1 1 0 0 0-1.42-.28z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>', $allowed_html );
        $svg_cold = wp_kses( '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>', $allowed_html );
        $svg_over = wp_kses( '<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>', $allowed_html );
        $out = '';
        // SLA badge (higher priority — show first).
        if ( 'overdue' === $sla_status ) {
            $out .= '<span class="leadite-fug-badge leadite-fug-badge--danger" title="' . esc_attr__( 'Overdue', 'leadite' ) . '">' . $svg_over . '</span> ';
        } elseif ( 'needs_attention' === $sla_status ) {
            $out .= '<span class="leadite-fug-badge leadite-fug-badge--warn" title="' . esc_attr__( 'Needs follow-up', 'leadite' ) . '">' . $svg_warn . '</span> ';
        }
        // Score badge.
        if ( $score >= $threshold ) {
            /* translators: %d: lead score value */
            $out .= '<span class="leadite-fug-badge leadite-fug-badge--hot" title="' . esc_attr( sprintf( __( 'Score: %d', 'leadite' ), $score ) ) . '">' . $svg_hot . '</span>';
        } elseif ( $score >= 20 ) {
            /* translators: %d: lead score value */
            $out .= '<span class="leadite-fug-badge leadite-fug-badge--warm" title="' . esc_attr( sprintf( __( 'Score: %d', 'leadite' ), $score ) ) . '">' . $svg_warn . '</span>';
        } elseif ( '' === $out ) {
            // Only show cold if no other badge already displayed.
            /* translators: %d: lead score value */
            $out .= '<span class="leadite-fug-badge leadite-fug-badge--cold" title="' . esc_attr( sprintf( __( 'Score: %d', 'leadite' ), $score ) ) . '">' . $svg_cold . '</span>';
        }
        return $out;
    }

    /**
     * Localized date.
     *
     * @param object $item Row.
     * @return string
     */
    public function column_created_at( $item ) {
        // current_time('mysql') is site-local time; get_gmt_from_date converts it
        // to GMT so strtotime() returns the correct Unix timestamp for wp_date().
        $ts = strtotime( get_gmt_from_date( $item->created_at ) );
        return esc_html( wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $ts ) );
    }

    /**
     * Fallback column renderer.
     *
     * @param object $item   Row.
     * @param string $column Column key.
     * @return string
     */
    public function column_default( $item, $column ) {
        return ( isset( $item->{$column} ) ? esc_html( $item->{$column} ) : '' );
    }

    /**
     * Prepare items with filters + pagination.
     */
    public function prepare_items() {
        $per_page = (int) Config::get( 'per_page', 25 );
        $paged = $this->get_pagenum();
        $orderby = ( isset( $_GET['orderby'] ) ? sanitize_key( wp_unslash( $_GET['orderby'] ) ) : 'created_at' );
        // phpcs:ignore WordPress.Security.NonceVerification
        $order = ( isset( $_GET['order'] ) ? sanitize_key( wp_unslash( $_GET['order'] ) ) : 'desc' );
        // phpcs:ignore WordPress.Security.NonceVerification
        $args = array(
            'search'    => ( isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : '' ),
            'source'    => ( isset( $_GET['source'] ) ? sanitize_text_field( wp_unslash( $_GET['source'] ) ) : '' ),
            'form'      => ( isset( $_GET['form'] ) ? sanitize_text_field( wp_unslash( $_GET['form'] ) ) : '' ),
            'status'    => ( isset( $_GET['status'] ) ? sanitize_text_field( wp_unslash( $_GET['status'] ) ) : '' ),
            'date_from' => ( isset( $_GET['from'] ) ? sanitize_text_field( wp_unslash( $_GET['from'] ) ) : '' ),
            'date_to'   => ( isset( $_GET['to'] ) ? sanitize_text_field( wp_unslash( $_GET['to'] ) ) : '' ),
            'orderby'   => $orderby,
            'order'     => $order,
            'per_page'  => $per_page,
            'page'      => $paged,
        );
        // Starred and assigned_to filters are Pro-only; ignore them in Free.
        $args['smart_view'] = '';
        $result = LeadsRepository::query( $args );
        $this->items = $result['items'];
        $this->total = $result['total'];
        // Batch-fetch all meta in one query to avoid N+1 on column_lead().
        $this->meta_map = LeadsRepository::find_many( $this->items );
        $this->set_pagination_args( array(
            'total_items' => $this->total,
            'per_page'    => $per_page,
            'total_pages' => (int) ceil( $this->total / $per_page ),
        ) );
        $this->_column_headers = array(
            $this->get_columns(),
            $this->get_hidden_columns(),
            $this->get_sortable_columns(),
            'lead'
        );
    }

    /**
     * Filter controls above the table.
     *
     * @param string $which top|bottom.
     */
    protected function extra_tablenav( $which ) {
        if ( 'top' !== $which ) {
            return;
        }
        $source = ( isset( $_GET['source'] ) ? sanitize_text_field( wp_unslash( $_GET['source'] ) ) : '' );
        // phpcs:ignore WordPress.Security.NonceVerification
        $form = ( isset( $_GET['form'] ) ? sanitize_text_field( wp_unslash( $_GET['form'] ) ) : '' );
        // phpcs:ignore WordPress.Security.NonceVerification
        $status = ( isset( $_GET['status'] ) ? sanitize_text_field( wp_unslash( $_GET['status'] ) ) : '' );
        // phpcs:ignore WordPress.Security.NonceVerification
        $from = ( isset( $_GET['from'] ) ? sanitize_text_field( wp_unslash( $_GET['from'] ) ) : '' );
        // phpcs:ignore WordPress.Security.NonceVerification
        $to = ( isset( $_GET['to'] ) ? sanitize_text_field( wp_unslash( $_GET['to'] ) ) : '' );
        // phpcs:ignore WordPress.Security.NonceVerification
        $starred = ( isset( $_GET['starred'] ) && '1' === $_GET['starred'] ? '1' : '' );
        // phpcs:ignore WordPress.Security.NonceVerification
        $assigned_to = ( isset( $_GET['assigned_to'] ) ? (int) $_GET['assigned_to'] : 0 );
        // phpcs:ignore WordPress.Security.NonceVerification
        echo '<div class="alignleft actions leadite-filters">';
        // Source.
        echo '<select name="source"><option value="">' . esc_html__( 'All sources', 'leadite' ) . '</option>';
        foreach ( LeadsRepository::sources() as $s ) {
            printf(
                '<option value="%s" %s>%s</option>',
                esc_attr( $s ),
                selected( $source, $s, false ),
                esc_html( $s )
            );
        }
        echo '</select> ';
        // Form.
        echo '<select name="form"><option value="">' . esc_html__( 'All forms', 'leadite' ) . '</option>';
        foreach ( LeadsRepository::form_names() as $f ) {
            printf(
                '<option value="%s" %s>%s</option>',
                esc_attr( $f ),
                selected( $form, $f, false ),
                esc_html( $f )
            );
        }
        echo '</select> ';
        // Status.
        $statuses = array(
            ''            => __( 'All statuses', 'leadite' ),
            'new'         => __( 'New', 'leadite' ),
            'read'        => __( 'Read', 'leadite' ),
            'in_progress' => __( 'In progress', 'leadite' ),
            'closed'      => __( 'Closed', 'leadite' ),
            'spam'        => __( 'Spam', 'leadite' ),
        );
        echo '<select name="status">';
        foreach ( $statuses as $val => $lbl ) {
            printf(
                '<option value="%s" %s>%s</option>',
                esc_attr( $val ),
                selected( $status, $val, false ),
                esc_html( $lbl )
            );
        }
        echo '</select> ';
        echo '<input type="date" name="from" value="' . esc_attr( $from ) . '"> ';
        echo '<input type="date" name="to" value="' . esc_attr( $to ) . '"> ';
        submit_button(
            __( 'Filter', 'leadite' ),
            'secondary',
            'filter_action',
            false
        );
        $has_filter = !empty( $source ) || !empty( $form ) || !empty( $status ) || !empty( $from ) || !empty( $to ) || !empty( $_GET['s'] ) || Pro::is_active() && ('' !== $starred || $assigned_to > 0 || isset( $_GET['tag_id'] ) && (int) $_GET['tag_id'] > 0);
        // phpcs:ignore WordPress.Security.NonceVerification
        if ( $has_filter ) {
            echo ' <a href="' . esc_url( admin_url( 'admin.php?page=leadite-leads' ) ) . '" class="button">' . esc_html__( 'Clear Filters', 'leadite' ) . '</a>';
        }
        echo '</div>';
    }

    /**
     * Empty-state message.
     */
    public function no_items() {
        esc_html_e( 'No leads yet. Once a visitor submits a connected form, it will appear here.', 'leadite' );
    }

    /**
     * Decode percent-encoded Hebrew/Arabic/Russian page URL paths to display readable page names.
     * Resolves URLs to local post/page titles where possible.
     *
     * @param string $url Page URL.
     * @return string Page label or path.
     */
    public static function get_page_label( $url ) {
        if ( empty( $url ) ) {
            return '—';
        }
        $post_id = url_to_postid( $url );
        if ( $post_id > 0 ) {
            return get_the_title( $post_id );
        }
        $path = wp_parse_url( $url, PHP_URL_PATH );
        if ( empty( $path ) || '/' === $path ) {
            return __( 'Home Page', 'leadite' );
        }
        return trim( urldecode( $path ), '/' );
    }

}
