<?php
/**
 * TitanCart — Product Tabs REST Controller.
 *
 * Manages storefront product-page tabs:
 *  • Built-in tabs (Description, Attributes, Reviews) — toggle per product
 *  • Sizing Chart — per-product structured table data
 *  • Rich-text custom tabs — global or per-product
 *  • Template tabs — registered by themes/extensions via hook
 *
 * All endpoints scoped under /products/{id}/tabs.
 *
 * @package TitanCart\REST\Products
 */

namespace TitanCart\REST\Products;

defined( 'ABSPATH' ) || exit;

use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
use WP_Error;

class TabsController {

    private const NS = 'titancart/v1';

    /* ────────────────────────────────────────────────────────────────────────
     *  Helpers
     * ──────────────────────────────────────────────────────────────────────── */

    /** @return \TitanCart\DB\Database */
    private function db() {
        return \titancart_db();
    }

    /** Fully-prefixed table name, e.g. wp_tc_product_tabs */
    private function t( string $name ): string {
        return $this->db()->table( $name );
    }

    /* ────────────────────────────────────────────────────────────────────────
     *  Route registration
     * ──────────────────────────────────────────────────────────────────────── */

    public function register_routes(): void {

        // Product-scoped tabs: GET list + POST create (same path, one registration)
        \register_rest_route( self::NS, '/products/(?P<id>[\d]+)/tabs', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_items' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'create_item' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

        // Batch-save per-product overrides (enable/disable toggles)
        \register_rest_route( self::NS, '/products/(?P<id>[\d]+)/tabs/overrides', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'save_overrides' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

        // Single tab: PUT update + DELETE (same path, one registration)
        \register_rest_route( self::NS, '/products/(?P<id>[\d]+)/tabs/(?P<tab_id>[\d]+)', [
            [
                'methods'             => 'PUT, PATCH',
                'callback'            => [ $this, 'update_item' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
            [
                'methods'             => WP_REST_Server::DELETABLE,
                'callback'            => [ $this, 'delete_item' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

        // Sizing chart: GET + POST (same path, one registration)
        \register_rest_route( self::NS, '/products/(?P<id>[\d]+)/sizing-chart', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_sizing_chart' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'save_sizing_chart' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

        // Global tabs: GET list + POST create (same path, one registration)
        \register_rest_route( self::NS, '/tabs', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_global_tabs' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [ $this, 'create_global_tab' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

        // Global single tab: PUT + DELETE (same path, one registration)
        \register_rest_route( self::NS, '/tabs/(?P<tab_id>[\d]+)', [
            [
                'methods'             => 'PUT, PATCH',
                'callback'            => [ $this, 'update_global_tab' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
            [
                'methods'             => WP_REST_Server::DELETABLE,
                'callback'            => [ $this, 'delete_global_tab' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );
    }

    /* ────────────────────────────────────────────────────────────────────────
     *  Permission
     * ──────────────────────────────────────────────────────────────────────── */

    public function admin_permission(): bool {
        return current_user_can( 'manage_options' );
    }

    /* ────────────────────────────────────────────────────────────────────────
     *  GET /products/{id}/tabs — merged list for product editor
     * ──────────────────────────────────────────────────────────────────────── */

    public function get_items( $request ): WP_REST_Response {
        $product_id = (int) $request['id'];
        $db         = $this->db();
        $lang       = 'en';
        $tTabs      = $this->t( 'product_tabs' );
        $tTr        = $this->t( 'product_tab_translations' );
        $tOv        = $this->t( 'product_tab_overrides' );
        $tSz        = $this->t( 'product_sizing_charts' );

        // 1. All global tabs (product_id IS NULL)
        $global = $db->getArray(
            "SELECT t.*, tr.title, tr.content
             FROM {$tTabs} t
             LEFT JOIN {$tTr} tr ON tr.tab_id = t.id AND tr.language_code = ?s
             WHERE t.product_id IS NULL
             ORDER BY t.position ASC",
            $lang
        );

        // 2. Per-product overrides
        $overrides_raw = $db->getArray(
            "SELECT tab_id, status, content_override FROM {$tOv} WHERE product_id = ?i",
            $product_id
        );
        $overrides = [];
        foreach ( $overrides_raw as $ov ) {
            $overrides[ (int) $ov['tab_id'] ] = $ov;
        }

        // 3. Merge overrides into global tabs
        $tabs = [];
        foreach ( $global as $tab ) {
            $tid = (int) $tab['id'];
            $tab['product_status'] = isset( $overrides[ $tid ] )
                ? $overrides[ $tid ]['status']
                : $tab['status'];  // inherit global default
            $tab['content_override'] = isset( $overrides[ $tid ] )
                ? $overrides[ $tid ]['content_override']
                : null;
            $tab['scope'] = 'global';
            $tabs[] = $tab;
        }

        // 4. Product-specific tabs (product_id = this product)
        $product_tabs = $db->getArray(
            "SELECT t.*, tr.title, tr.content
             FROM {$tTabs} t
             LEFT JOIN {$tTr} tr ON tr.tab_id = t.id AND tr.language_code = ?s
             WHERE t.product_id = ?i
             ORDER BY t.position ASC",
            $lang, $product_id
        );
        foreach ( $product_tabs as $pt ) {
            $pt['product_status'] = $pt['status'];
            $pt['scope']          = 'product';
            $tabs[] = $pt;
        }

        // 5. Allow themes/extensions to register template tabs
        $tabs = \apply_filters( 'titancart_product_tabs', $tabs, $product_id );

        // 6. Sizing chart data (separate payload)
        $sizing = $db->getRow(
            "SELECT * FROM {$tSz} WHERE product_id = ?i",
            $product_id
        );
        if ( $sizing && ! empty( $sizing['chart_data'] ) ) {
            $sizing['chart_data'] = json_decode( $sizing['chart_data'], true );
        }

        return new WP_REST_Response( [
            'tabs'         => $tabs,
            'sizing_chart' => $sizing ?: null,
        ], 200 );
    }

    /* ────────────────────────────────────────────────────────────────────────
     *  POST /products/{id}/tabs/overrides — batch save toggles
     *
     *  Body: { overrides: [ { tab_id: 1, status: "active"|"disabled", content_override: "..." }, ... ] }
     * ──────────────────────────────────────────────────────────────────────── */

    public function save_overrides( $request ): WP_REST_Response {
        $product_id = (int) $request['id'];
        $body       = $request->get_json_params();
        $overrides  = $body['overrides'] ?? [];
        $db         = $this->db();
        $tOv        = $this->t( 'product_tab_overrides' );

        foreach ( $overrides as $ov ) {
            $tab_id = (int) ( $ov['tab_id'] ?? 0 );
            $status = in_array( $ov['status'] ?? '', [ 'active', 'disabled' ], true )
                ? $ov['status']
                : 'active';
            $content_override = isset( $ov['content_override'] ) ? trim( $ov['content_override'] ) : null;

            if ( ! $tab_id ) {
                continue;
            }

            // Upsert
            $existing = $db->getRow(
                "SELECT id FROM {$tOv} WHERE tab_id = ?i AND product_id = ?i",
                $tab_id, $product_id
            );

            if ( $existing ) {
                $db->query(
                    "UPDATE {$tOv} SET status = ?s, content_override = ?s WHERE id = ?i",
                    $status, $content_override, (int) $existing['id']
                );
            } else {
                $db->query(
                    "INSERT INTO {$tOv} (tab_id, product_id, status, content_override) VALUES (?i, ?i, ?s, ?s)",
                    $tab_id, $product_id, $status, $content_override
                );
            }
        }

        return new WP_REST_Response( [ 'saved' => count( $overrides ) ], 200 );
    }

    /* ────────────────────────────────────────────────────────────────────────
     *  POST /products/{id}/tabs — create product-specific richtext tab
     * ──────────────────────────────────────────────────────────────────────── */

    public function create_item( $request ): WP_REST_Response {
        $product_id = (int) $request['id'];
        $body       = $request->get_json_params();
        $title      = sanitize_text_field( $body['title'] ?? '' );
        $content    = wp_kses_post( $body['content'] ?? '' );
        $position   = (int) ( $body['position'] ?? 999 );

        if ( empty( $title ) ) {
            return new WP_REST_Response( [ 'error' => 'Title is required.' ], 400 );
        }

        $db    = $this->db();
        $tTabs = $this->t( 'product_tabs' );
        $tTr   = $this->t( 'product_tab_translations' );

        $db->query(
            "INSERT INTO {$tTabs} (tab_type, tab_key, product_id, position, status, is_primary)
             VALUES (?s, ?s, ?i, ?i, ?s, ?i)",
            'richtext',
            sanitize_title( $title ),
            $product_id,
            $position,
            'active',
            0
        );
        $tab_id = $db->lastInsertId();

        $db->query(
            "INSERT INTO {$tTr} (tab_id, language_code, title, content) VALUES (?i, ?s, ?s, ?s)",
            $tab_id, 'en', $title, $content
        );

        return new WP_REST_Response( [ 'tab_id' => $tab_id ], 201 );
    }

    /* ────────────────────────────────────────────────────────────────────────
     *  PUT /products/{id}/tabs/{tab_id} — update product-specific tab
     * ──────────────────────────────────────────────────────────────────────── */

    public function update_item( $request ): WP_REST_Response {
        $tab_id = (int) $request['tab_id'];
        $body   = $request->get_json_params();
        $db     = $this->db();
        $tTabs  = $this->t( 'product_tabs' );
        $tTr    = $this->t( 'product_tab_translations' );

        $tab = $db->getRow( "SELECT * FROM {$tTabs} WHERE id = ?i", $tab_id );
        if ( ! $tab ) {
            return new WP_REST_Response( [ 'error' => 'Tab not found.' ], 404 );
        }

        // Update main record fields if provided
        $updates = [];
        if ( isset( $body['position'] ) ) {
            $updates[] = [ 'position', (int) $body['position'] ];
        }
        if ( isset( $body['status'] ) && in_array( $body['status'], [ 'active', 'disabled' ], true ) ) {
            $updates[] = [ 'status', $body['status'] ];
        }
        if ( ! empty( $updates ) ) {
            $set_parts = [];
            $params    = [];
            foreach ( $updates as [ $col, $val ] ) {
                $set_parts[] = "$col = ?s";
                $params[]    = $val;
            }
            $params[] = $tab_id;
            $db->query(
                "UPDATE {$tTabs} SET " . implode( ', ', $set_parts ) . " WHERE id = ?i",
                ...$params
            );
        }

        // Update translations
        if ( isset( $body['title'] ) || isset( $body['content'] ) ) {
            $tr = $db->getRow(
                "SELECT id FROM {$tTr} WHERE tab_id = ?i AND language_code = ?s",
                $tab_id, 'en'
            );
            $tr_data = [];
            if ( isset( $body['title'] ) ) {
                $tr_data['title'] = sanitize_text_field( $body['title'] );
            }
            if ( isset( $body['content'] ) ) {
                $tr_data['content'] = wp_kses_post( $body['content'] );
            }
            if ( $tr ) {
                $set_parts = [];
                $params    = [];
                foreach ( $tr_data as $col => $val ) {
                    $set_parts[] = "$col = ?s";
                    $params[]    = $val;
                }
                $params[] = (int) $tr['id'];
                $db->query(
                    "UPDATE {$tTr} SET " . implode( ', ', $set_parts ) . " WHERE id = ?i",
                    ...$params
                );
            } else {
                $db->query(
                    "INSERT INTO {$tTr} (tab_id, language_code, title, content) VALUES (?i, ?s, ?s, ?s)",
                    $tab_id, 'en',
                    $tr_data['title'] ?? '',
                    $tr_data['content'] ?? ''
                );
            }
        }

        return new WP_REST_Response( [ 'updated' => true ], 200 );
    }

    /* ────────────────────────────────────────────────────────────────────────
     *  DELETE /products/{id}/tabs/{tab_id}
     * ──────────────────────────────────────────────────────────────────────── */

    public function delete_item( $request ): WP_REST_Response {
        $tab_id = (int) $request['tab_id'];
        $db     = $this->db();
        $tTabs  = $this->t( 'product_tabs' );
        $tTr    = $this->t( 'product_tab_translations' );
        $tOv    = $this->t( 'product_tab_overrides' );

        $tab = $db->getRow( "SELECT * FROM {$tTabs} WHERE id = ?i", $tab_id );
        if ( ! $tab ) {
            return new WP_REST_Response( [ 'error' => 'Tab not found.' ], 404 );
        }
        if ( (int) $tab['is_primary'] === 1 ) {
            return new WP_REST_Response( [ 'error' => 'Primary tabs cannot be deleted.' ], 403 );
        }

        $db->query( "DELETE FROM {$tTr} WHERE tab_id = ?i", $tab_id );
        $db->query( "DELETE FROM {$tOv} WHERE tab_id = ?i", $tab_id );
        $db->query( "DELETE FROM {$tTabs} WHERE id = ?i", $tab_id );

        return new WP_REST_Response( [ 'deleted' => true ], 200 );
    }

    /* ────────────────────────────────────────────────────────────────────────
     *  Sizing chart endpoints
     * ──────────────────────────────────────────────────────────────────────── */

    public function get_sizing_chart( $request ): WP_REST_Response {
        $product_id = (int) $request['id'];
        $db         = $this->db();
        $tSz        = $this->t( 'product_sizing_charts' );

        $row = $db->getRow(
            "SELECT * FROM {$tSz} WHERE product_id = ?i",
            $product_id
        );

        if ( $row && ! empty( $row['chart_data'] ) ) {
            $row['chart_data'] = json_decode( $row['chart_data'], true );
        }

        return new WP_REST_Response( $row ?: [
            'product_id' => $product_id,
            'chart_data' => [
                'unit'    => 'in',
                'headers' => [ 'Size', 'Chest', 'Waist', 'Hips' ],
                'rows'    => [
                    [ 'S',  '34-36', '28-30', '34-36' ],
                    [ 'M',  '38-40', '32-34', '38-40' ],
                    [ 'L',  '42-44', '36-38', '42-44' ],
                    [ 'XL', '46-48', '40-42', '46-48' ],
                ],
            ],
            'notes' => '',
        ], 200 );
    }

    public function save_sizing_chart( $request ): WP_REST_Response {
        $product_id = (int) $request['id'];
        $body       = $request->get_json_params();
        $db         = $this->db();
        $tSz        = $this->t( 'product_sizing_charts' );

        $chart_data = $body['chart_data'] ?? null;
        $notes      = sanitize_textarea_field( $body['notes'] ?? '' );

        if ( ! $chart_data || ! is_array( $chart_data ) ) {
            return new WP_REST_Response( [ 'error' => 'chart_data is required.' ], 400 );
        }

        // Sanitise chart_data
        $clean = [
            'unit'    => in_array( $chart_data['unit'] ?? '', [ 'in', 'cm' ], true ) ? $chart_data['unit'] : 'in',
            'headers' => array_map( 'sanitize_text_field', $chart_data['headers'] ?? [] ),
            'rows'    => [],
        ];
        foreach ( ( $chart_data['rows'] ?? [] ) as $row ) {
            $clean['rows'][] = array_map( 'sanitize_text_field', (array) $row );
        }

        $json = wp_json_encode( $clean );

        // Upsert
        $existing = $db->getRow(
            "SELECT id FROM {$tSz} WHERE product_id = ?i",
            $product_id
        );

        if ( $existing ) {
            $db->query(
                "UPDATE {$tSz} SET chart_data = ?s, notes = ?s WHERE id = ?i",
                $json, $notes, (int) $existing['id']
            );
        } else {
            $db->query(
                "INSERT INTO {$tSz} (product_id, chart_data, notes) VALUES (?i, ?s, ?s)",
                $product_id, $json, $notes
            );
        }

        return new WP_REST_Response( [ 'saved' => true ], 200 );
    }

    /* ────────────────────────────────────────────────────────────────────────
     *  Global tabs CRUD (admin sidebar page / settings)
     * ──────────────────────────────────────────────────────────────────────── */

    public function get_global_tabs( $request ): WP_REST_Response {
        $db    = $this->db();
        $tTabs = $this->t( 'product_tabs' );
        $tTr   = $this->t( 'product_tab_translations' );

        $tabs = $db->getArray(
            "SELECT t.*, tr.title, tr.content
             FROM {$tTabs} t
             LEFT JOIN {$tTr} tr ON tr.tab_id = t.id AND tr.language_code = ?s
             WHERE t.product_id IS NULL
             ORDER BY t.position ASC",
            'en'
        );
        return new WP_REST_Response( $tabs, 200 );
    }

    public function create_global_tab( $request ): WP_REST_Response {
        $body    = $request->get_json_params();
        $title   = sanitize_text_field( $body['title'] ?? '' );
        $content = wp_kses_post( $body['content'] ?? '' );
        $type    = in_array( $body['tab_type'] ?? '', [ 'richtext', 'sizing_chart', 'template' ], true )
            ? $body['tab_type']
            : 'richtext';

        if ( empty( $title ) ) {
            return new WP_REST_Response( [ 'error' => 'Title is required.' ], 400 );
        }

        $db       = $this->db();
        $tTabs    = $this->t( 'product_tabs' );
        $tTr      = $this->t( 'product_tab_translations' );
        $position = (int) ( $body['position'] ?? 999 );
        $template = sanitize_text_field( $body['template_path'] ?? '' );

        $db->query(
            "INSERT INTO {$tTabs} (tab_type, tab_key, product_id, template_path, position, status, is_primary)
             VALUES (?s, ?s, NULL, ?s, ?i, ?s, ?i)",
            $type,
            sanitize_title( $title ),
            $template ?: null,
            $position,
            'active',
            0
        );
        $tab_id = $db->lastInsertId();

        $db->query(
            "INSERT INTO {$tTr} (tab_id, language_code, title, content) VALUES (?i, ?s, ?s, ?s)",
            $tab_id, 'en', $title, $content
        );

        return new WP_REST_Response( [ 'tab_id' => $tab_id ], 201 );
    }

    public function update_global_tab( $request ): WP_REST_Response {
        return $this->update_item( $request );
    }

    public function delete_global_tab( $request ): WP_REST_Response {
        return $this->delete_item( $request );
    }
}
