<?php

/**
 * SocialPromoter Site Profile resolver.
 *
 * Reads the shared `publisherkits_site_profile` option - the same structure
 * Insight Engine writes - so social copy can be framed around the
 * publication's audience and goals. Works whether or not Insight Engine is
 * active: the option is shared and owned by no single plugin, so SocialPromoter
 * reads it directly rather than depending on the Insight Engine classes.
 *
 * If the profile has not been populated anywhere, SocialPromoter offers a
 * lightweight subset (primary goal + audience description) in its own Settings
 * that writes back to the same shared option via a partial merge, so anything
 * entered here is picked up by Insight Engine too, and vice versa.
 *
 * Since v1.51.0 the core-owned PK Site Profile (PKCORE_Profile, bundled PK
 * Core Library) leads the AI framing when populated - sector, house style and
 * context - with the legacy shared option composing after it. The legacy
 * option is unchanged and still read/written as before.
 *
 * @package PublisherKits_SocialPromoter
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
/**
 * Class PKITS_SP_Site_Profile
 */
class PKITS_SP_Site_Profile {
    /** @var string Shared cross-plugin option key (also written by Insight Engine). */
    const OPTION = 'publisherkits_site_profile';

    /**
     * Human-readable labels for the primary/secondary goal slugs.
     *
     * Mirrors the Insight Engine goal vocabulary so the two plugins describe
     * goals identically.
     *
     * @return array
     */
    public static function goal_labels() {
        return array(
            'organic_traffic'    => 'Grow organic search traffic',
            'email_subscribers'  => 'Build an email audience',
            'leads_enquiries'    => 'Generate leads and enquiries',
            'advertising'        => 'Maximise advertising revenue',
            'advertiser_results' => 'Deliver results for advertisers',
            'brand_awareness'    => 'Build brand awareness',
            'community'          => 'Build a community or membership',
            'ecommerce'          => 'Drive sales',
            'donations'          => 'Drive donations or fundraising',
            'education'          => 'Educate readers',
            'events'             => 'Drive event attendance or bookings',
        );
    }

    /**
     * Get the raw shared site profile with defaults applied.
     *
     * @return array
     */
    public static function get() {
        $defaults = array(
            'site_description'     => '',
            'site_type'            => '',
            'audience_description' => '',
            'audience_sectors'     => array(),
            'audience_seniority'   => array(),
            'primary_goal'         => '',
            'secondary_goals'      => array(),
            'content_goals'        => array(),
        );
        $stored = get_option( self::OPTION, array() );
        $stored = ( is_array( $stored ) ? $stored : array() );
        return array_merge( $defaults, $stored );
    }

    /**
     * Whether the shared profile carries enough to be useful for framing.
     *
     * @return bool
     */
    public static function has_profile() {
        $p = self::get();
        return '' !== trim( (string) $p['audience_description'] ) || '' !== trim( (string) $p['primary_goal'] ) || '' !== trim( (string) $p['site_description'] );
    }

    /**
     * Save a lightweight subset back to the shared profile, preserving any
     * richer fields written by Insight Engine (partial merge).
     *
     * NEVER BLANKS A POPULATED FIELD. This form is the lightweight fallback that
     * only renders when Insight Engine has not populated the profile, so an empty
     * value arriving here means "this form did not carry the field", not "the
     * publisher cleared it". Writing that empty string through destroyed Insight
     * Engine's primary_goal on hrzone.com - see PK-CORE-SPEC-01, Defect 3. The
     * caller in PKITS_SP_Admin now sends only the keys the request carried; this
     * guard is the second line of defence and the one that survives a new caller.
     *
     * Clearing a value is done in Insight Engine, which owns the full editor.
     *
     * @param array $subset Keys among: audience_description, primary_goal, site_description.
     * @return void
     */
    public static function save_subset( array $subset ) {
        $current = get_option( self::OPTION, array() );
        $current = ( is_array( $current ) ? $current : array() );
        $allowed = array('audience_description', 'primary_goal', 'site_description');
        $changed = false;
        foreach ( $subset as $key => $value ) {
            if ( !in_array( $key, $allowed, true ) ) {
                continue;
            }
            $value = ( is_string( $value ) ? sanitize_textarea_field( $value ) : $value );
            $incoming_empty = '' === $value || array() === $value || null === $value;
            $existing = ( isset( $current[$key] ) ? $current[$key] : '' );
            $existing_set = !('' === $existing || array() === $existing || null === $existing);
            if ( $incoming_empty && $existing_set ) {
                continue;
                // Never blank a populated field from this partial path.
            }
            $current[$key] = $value;
            $changed = true;
        }
        if ( !$changed ) {
            return;
        }
        update_option( self::OPTION, $current, false );
    }

    /**
     * The publication context (brand voice / free-text context) used in every
     * AI prompt's PUBLICATION CONTEXT block.
     *
     * The shared PK Site Profile's context (bundled PK Core) is the source of
     * truth when populated; the ownerless publisherkits_site_context option
     * and this plugin's own setting remain as pre-core fallbacks so nothing
     * regresses on sites that have not run the profile setup. The Settings
     * screen's "Brand voice / extra context" field edits all of them in step
     * (see the save handler in PKITS_SP_Admin).
     *
     * @return string '' when no context is set anywhere.
     */
    public static function publication_context() {
        if ( class_exists( 'PKCORE_Profile' ) && PKCORE_Profile::is_populated() ) {
            $context = trim( (string) PKCORE_Profile::get_context() );
            if ( '' !== $context ) {
                return $context;
            }
        }
        $shared = trim( (string) get_option( 'publisherkits_site_context', '' ) );
        if ( '' !== $shared ) {
            return $shared;
        }
        $settings = get_option( 'pkits_sp_settings', array() );
        return ( is_array( $settings ) && isset( $settings['site_context'] ) ? trim( (string) $settings['site_context'] ) : '' );
    }

}
