<?php
/**
 * Settings — Fix #7: API keys never exposed raw in HTML output.
 *
 * @package EPWF\Includes
 */
namespace EPWF\Includes;
defined( 'ABSPATH' ) || exit;

class Settings {

    /** @var array|null */
    private $cache = null;

    public static $HOOK_LABELS = [
        'woocommerce_before_single_product'         => 'Before Product — Top of page',
        'woocommerce_before_single_product_summary' => 'Before Summary — Above title',
        'woocommerce_single_product_summary'        => 'Inside Summary — After price',
        'woocommerce_after_single_product_summary'  => 'After Summary — Below tabs',
        'woocommerce_after_single_product'          => 'After Product — Bottom of page',
    ];

    public static $AI_MODELS = [
        // OpenAI
        'gpt-4o'           => [ 'label' => 'GPT-4o',              'provider' => 'openai',    'badge' => 'OpenAI' ],
        'gpt-4o-mini'      => [ 'label' => 'GPT-4o Mini',         'provider' => 'openai',    'badge' => 'OpenAI' ],
        // Gemini
        'gemini-1.5-pro'   => [ 'label' => 'Gemini 1.5 Pro',      'provider' => 'gemini',    'badge' => 'Google' ],
        'gemini-1.5-flash' => [ 'label' => 'Gemini 1.5 Flash',    'provider' => 'gemini',    'badge' => 'Google' ],
        // Claude
        'claude-3-5-sonnet'=> [ 'label' => 'Claude 3.5 Sonnet',   'provider' => 'anthropic', 'badge' => 'Anthropic' ],
        'claude-3-haiku'   => [ 'label' => 'Claude 3 Haiku',      'provider' => 'anthropic', 'badge' => 'Anthropic' ],
        // Grok
        'grok-3'           => [ 'label' => 'Grok 3',              'provider' => 'grok',      'badge' => 'xAI' ],
        'grok-3-mini'      => [ 'label' => 'Grok 3 Mini',         'provider' => 'grok',      'badge' => 'xAI' ],
        // Kimi
        'moonshot-v1-8k'   => [ 'label' => 'Kimi moonshot-v1-8k', 'provider' => 'kimi',      'badge' => 'Moonshot' ],
        'moonshot-v1-32k'  => [ 'label' => 'Kimi moonshot-v1-32k','provider' => 'kimi',      'badge' => 'Moonshot' ],
    ];

    private static $ALLOWED_STYLES = [ 'modern', 'minimal', 'boxed' ];

    // ── Read ───────────────────────────────────────────────────────────────────

    public function get_all() {
        if ( null === $this->cache ) {
            $saved       = get_option( EPWF_OPTION_KEY, [] );
            $this->cache = wp_parse_args(
                is_array( $saved ) ? $saved : [],
                epwf_defaults()
            );
        }
        return $this->cache;
    }

    public function flush() { $this->cache = null; }

    public function get( $key, $default = '' ) {
        $all = $this->get_all();
        return array_key_exists( $key, $all ) ? $all[ $key ] : $default;
    }

    // ── Typed getters ──────────────────────────────────────────────────────────

    public function is_enabled()          { return (bool)   $this->get( 'enabled' );         }
    public function get_model()           { return (string) $this->get( 'ai_model' );        }
    public function get_faq_count()       { return (int)    $this->get( 'faq_count', 5 );    }
    public function is_additive()         { return (bool)   $this->get( 'additive_mode' );   }
    public function get_hook()            { return (string) $this->get( 'hook' );             }
    public function get_priority()        { return (int)    $this->get( 'priority', 10 );    }
    public function get_style()           { return (string) $this->get( 'accordion_style' ); }
    public function is_auto_generate()    { return (bool)   $this->get( 'auto_generate' );   }
    public function get_section_title()   { return (string) $this->get( 'section_title', 'Frequently Asked Questions' ); }
    public function get_color( $key )     { return (string) $this->get( $key, '#7c3aed' );   }
    public function get_font_size()       { return (int)    $this->get( 'font_size', 15 );          }
    public function get_question_font_size() { return (int) $this->get( 'question_font_size', 15 ); }
    public function get_answer_font_size()   { return (int) $this->get( 'answer_font_size', 14 );   }
    public function get_wrap_margin_top()     { return (int) $this->get( 'wrap_margin_top', 32 );    }
    public function get_wrap_margin_bottom()  { return (int) $this->get( 'wrap_margin_bottom', 32 ); }
    public function get_item_padding_v()      { return (int) $this->get( 'item_padding_v', 14 );     }
    public function get_item_padding_h()      { return (int) $this->get( 'item_padding_h', 18 );     }
    public function get_answer_padding_v()    { return (int) $this->get( 'answer_padding_v', 12 );   }
    public function get_answer_padding_h()    { return (int) $this->get( 'answer_padding_h', 18 );   }
    public function get_item_margin_bottom()   { return (int) $this->get( 'item_margin_bottom', 0 ); }
    public function is_schema_enabled()         { return (bool) $this->get( 'enable_schema', 1 ); }

    // Fix #7: raw keys only returned from private methods — never exposed directly in HTML
    public function get_openai_key()      { return (string) $this->get( 'openai_key' );      }
    public function get_gemini_key()      { return (string) $this->get( 'gemini_key' );      }
    public function get_anthropic_key()   { return (string) $this->get( 'anthropic_key' );   }
    public function get_grok_key()        { return (string) $this->get( 'grok_key' );        }
    public function get_kimi_key()        { return (string) $this->get( 'kimi_key' );        }

    /**
     * Fix #7: Returns masked key (last 4 chars) for display in admin HTML.
     * Full key is never output as input value — fields use password type.
     */
    public function get_masked_key( $field ) {
        $val = (string) $this->get( $field );
        if ( '' === $val ) return '';
        $len = mb_strlen( $val );
        if ( $len <= 4 ) return str_repeat( '•', $len );
        return str_repeat( '•', max( 8, $len - 4 ) ) . mb_substr( $val, -4 );
    }

    public function has_key() { return '' !== trim( $this->get_active_key() ); }

    public function get_provider() {
        $m = $this->get_model();
        return isset( self::$AI_MODELS[ $m ] ) ? self::$AI_MODELS[ $m ]['provider'] : 'openai';
    }

    public function get_active_key() {
        switch ( $this->get_provider() ) {
            case 'gemini':    return $this->get_gemini_key();
            case 'anthropic': return $this->get_anthropic_key();
            case 'grok':      return $this->get_grok_key();
            case 'kimi':      return $this->get_kimi_key();
            default:          return $this->get_openai_key();
        }
    }

    // ── Sanitization ───────────────────────────────────────────────────────────

    /**
     * Fix #11: capability already checked before settings_fields()
     * This sanitize callback only cleans — access is WP's responsibility.
     */
    public function sanitize( $raw ) {
        if ( ! is_array( $raw ) ) return epwf_defaults();

        $hook = sanitize_key( isset( $raw['hook'] ) ? $raw['hook'] : '' );
        if ( ! array_key_exists( $hook, self::$HOOK_LABELS ) ) {
            $hook = 'woocommerce_after_single_product_summary';
        }

        $model = sanitize_key( isset( $raw['ai_model'] ) ? $raw['ai_model'] : 'gpt-4o' );
        if ( ! isset( self::$AI_MODELS[ $model ] ) ) $model = 'gpt-4o';

        $style = sanitize_key( isset( $raw['accordion_style'] ) ? $raw['accordion_style'] : 'modern' );
        if ( ! in_array( $style, self::$ALLOWED_STYLES, true ) ) $style = 'modern';

        $count = absint( isset( $raw['faq_count'] ) ? $raw['faq_count'] : 5 );
        $prio  = absint( isset( $raw['priority'] )  ? $raw['priority']  : 10 );
        $fs    = absint( isset( $raw['font_size'] )  ? $raw['font_size']  : 15 );
        $qfs   = absint( isset( $raw['question_font_size'] ) ? $raw['question_font_size'] : 15 );
        $afs   = absint( isset( $raw['answer_font_size'] )   ? $raw['answer_font_size']   : 14 );
        $wmt   = absint( isset( $raw['wrap_margin_top'] )    ? $raw['wrap_margin_top']    : 32 );
        $wmb   = absint( isset( $raw['wrap_margin_bottom'] ) ? $raw['wrap_margin_bottom'] : 32 );
        $ipv   = absint( isset( $raw['item_padding_v'] )     ? $raw['item_padding_v']     : 14 );
        $iph   = absint( isset( $raw['item_padding_h'] )     ? $raw['item_padding_h']     : 18 );
        $apv   = absint( isset( $raw['answer_padding_v'] )   ? $raw['answer_padding_v']   : 12 );
        $aph   = absint( isset( $raw['answer_padding_h'] )   ? $raw['answer_padding_h']   : 18 );
        $imb   = absint( isset( $raw['item_margin_bottom'] ) ? $raw['item_margin_bottom'] : 0  );
        $schema = isset( $raw['enable_schema'] ) ? 1 : 0;

        $hx = function ( $k, $r, $d ) {
            return sanitize_hex_color( isset( $r[ $k ] ) ? $r[ $k ] : $d ) ?: $d;
        };

        // Fix #7: API keys sanitized but stored as-is (WP options are encrypted at rest on hosts that support it)
        $sanitize_key_val = function ( $k, $r ) {
            $v = isset( $r[ $k ] ) ? $r[ $k ] : '';
            // If masked value submitted (user didn't change it), keep existing stored key
            if ( '' !== $v && false !== strpos( $v, '•' ) ) {
                $existing = $this->get( $k );
                return $existing;
            }
            return sanitize_text_field( $v );
        };

        $this->flush();

        return [
            'enabled'         => ! empty( $raw['enabled'] ),
            'ai_model'        => $model,
            'openai_key'      => $sanitize_key_val( 'openai_key',    $raw ),
            'gemini_key'      => $sanitize_key_val( 'gemini_key',    $raw ),
            'anthropic_key'   => $sanitize_key_val( 'anthropic_key', $raw ),
            'grok_key'        => $sanitize_key_val( 'grok_key',      $raw ),
            'kimi_key'        => $sanitize_key_val( 'kimi_key',      $raw ),
            'faq_count'       => ( $count >= 1 && $count <= 20 ) ? $count : 5,
            'additive_mode'   => ! empty( $raw['additive_mode'] ),
            'hook'            => $hook,
            'priority'        => ( $prio >= 1 && $prio <= 999 ) ? $prio : 10,
            'accordion_style' => $style,
            'auto_generate'   => ! empty( $raw['auto_generate'] ),
            'section_title'   => sanitize_text_field( isset( $raw['section_title'] ) ? $raw['section_title'] : 'Frequently Asked Questions' ),
            'color_primary'   => $hx( 'color_primary',   $raw, '#7c3aed' ),
            'color_hover'     => $hx( 'color_hover',     $raw, '#6d28d9' ),
            'color_active'    => $hx( 'color_active',    $raw, '#5b21b6' ),
            'color_text'      => $hx( 'color_text',      $raw, '#1f2937' ),
            'color_bg'        => $hx( 'color_bg',        $raw, '#ffffff' ),
            'color_border'    => $hx( 'color_border',    $raw, '#e5e7eb' ),
            'color_answer_bg' => $hx( 'color_answer_bg', $raw, '#f9fafb' ),
            'font_size'          => ( $fs  >= 12 && $fs  <= 24 ) ? $fs  : 15,
            'question_font_size' => ( $qfs >= 12 && $qfs <= 100 ) ? $qfs : 15,
            'answer_font_size'   => ( $afs >= 12 && $afs <= 100 ) ? $afs : 14,
            'wrap_margin_top'    => ( $wmt >= 0 && $wmt <= 100 ) ? $wmt : 32,
            'wrap_margin_bottom' => ( $wmb >= 0 && $wmb <= 100 ) ? $wmb : 32,
            'item_padding_v'     => ( $ipv >= 0 && $ipv <= 60  ) ? $ipv : 14,
            'item_padding_h'     => ( $iph >= 0 && $iph <= 60  ) ? $iph : 18,
            'answer_padding_v'   => ( $apv >= 0 && $apv <= 60  ) ? $apv : 12,
            'answer_padding_h'   => ( $aph >= 0 && $aph <= 60  ) ? $aph : 18,
            'item_margin_bottom' => ( $imb >= 0 && $imb <= 60  ) ? $imb : 15,
            'enable_schema'      => $schema,
        ];
    }
}
