<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

trait Niwa_AI_Chat_Daily_Reports {

    public function maybe_send_daily_report( $force = false ) {
        $settings = $this->get_admin_autonomy_settings();
        if ( empty( $settings['enabled'] ) || ( empty( $settings['daily_report_enabled'] ) && ! $force ) ) {
            return array(
                'success' => true,
                'sent'    => false,
                'reason'  => 'disabled',
            );
        }

        $due = $force ? $this->get_forced_report_date() : $this->get_due_report_date( $settings );
        if ( empty( $due['due'] ) ) {
            return array(
                'success' => true,
                'sent'    => false,
                'reason'  => 'not_due',
            );
        }

        $state       = $this->get_daily_report_state();
        $report_date = isset( $due['report_date'] ) ? (string) $due['report_date'] : '';
        if ( ! $force && $this->should_defer_initial_daily_report( $state, $report_date ) ) {
            $this->save_daily_report_state(
                array(
                    'last_completed_report_date' => $report_date,
                    'last_attempt_report_date'   => '',
                    'last_status'                => 'initialized',
                    'last_reason'                => 'initial_daily_report_deferred',
                    'last_sent_at'               => 0,
                    'last_attempt_at'            => 0,
                    'last_summary'               => '',
                    'last_error'                 => '',
                )
            );

            return array(
                'success' => true,
                'sent'    => false,
                'reason'  => 'initial_daily_report_deferred',
            );
        }

        if ( ! $force && '' !== $report_date && $report_date === (string) $state['last_completed_report_date'] ) {
            return array(
                'success' => true,
                'sent'    => false,
                'reason'  => 'already_completed',
            );
        }

        if ( ! $force && $this->is_daily_report_retry_cooled_down( $state, $report_date ) ) {
            return array(
                'success' => true,
                'sent'    => false,
                'reason'  => 'cooldown',
            );
        }

        if ( ! $this->acquire_daily_report_lock( $report_date, 300 ) ) {
            return array(
                'success' => true,
                'sent'    => false,
                'reason'  => 'locked',
            );
        }

        try {
            $state = $this->get_daily_report_state();
            if ( ! $force && '' !== $report_date && $report_date === (string) $state['last_completed_report_date'] ) {
                return array(
                    'success' => true,
                    'sent'    => false,
                    'reason'  => 'already_completed',
                );
            }

            $snapshot = $this->build_daily_report_snapshot( 'yesterday' );
            if ( empty( $snapshot['noteworthy'] ) ) {
                $this->save_daily_report_state(
                    array(
                        'last_completed_report_date' => $report_date,
                        'last_attempt_report_date'   => $report_date,
                        'last_status'                => 'skipped',
                        'last_reason'                => 'no_good_news',
                        'last_sent_at'               => isset( $state['last_sent_at'] ) ? intval( $state['last_sent_at'] ) : 0,
                        'last_attempt_at'            => time(),
                        'last_summary'               => '',
                        'last_error'                 => '',
                    )
                );

                return array(
                    'success' => true,
                    'sent'    => false,
                    'reason'  => 'no_good_news',
                );
            }

            $dispatch = $this->dispatch_daily_report_to_main_agent( $snapshot, $report_date );
            if ( empty( $dispatch['success'] ) || empty( $dispatch['queued'] ) ) {
                $dispatch_reason = isset( $dispatch['reason'] ) ? (string) $dispatch['reason'] : 'actor_enqueue_failed';
                $this->save_daily_report_state(
                    array(
                        'last_completed_report_date' => isset( $state['last_completed_report_date'] ) ? (string) $state['last_completed_report_date'] : '',
                        'last_attempt_report_date'   => $report_date,
                        'last_status'                => $dispatch_reason,
                        'last_reason'                => $dispatch_reason,
                        'last_sent_at'               => isset( $state['last_sent_at'] ) ? intval( $state['last_sent_at'] ) : 0,
                        'last_attempt_at'            => time(),
                        'last_summary'               => '',
                        'last_error'                 => isset( $dispatch['error'] ) ? (string) $dispatch['error'] : '',
                    )
                );

                return array(
                    'success' => false,
                    'sent'    => false,
                    'queued'  => false,
                    'reason'  => $dispatch_reason,
                    'error'   => isset( $dispatch['error'] ) ? (string) $dispatch['error'] : '',
                );
            }

            $target = isset( $dispatch['target'] ) && is_array( $dispatch['target'] ) ? $dispatch['target'] : array();
            $target_label = trim( ( isset( $target['channel'] ) ? (string) $target['channel'] : '' ) . ':' . ( isset( $target['chat_id'] ) ? (string) $target['chat_id'] : '' ), ':' );
            $this->save_daily_report_state(
                array(
                    'last_completed_report_date' => $report_date,
                    'last_attempt_report_date'   => $report_date,
                    'last_status'                => 'queued',
                    'last_reason'                => isset( $dispatch['reason'] ) ? (string) $dispatch['reason'] : 'queued_actor',
                    'last_sent_at'               => isset( $state['last_sent_at'] ) ? intval( $state['last_sent_at'] ) : 0,
                    'last_attempt_at'            => time(),
                    'last_summary'               => $this->truncate_block( 'Morning report queued for main founder agent' . ( '' !== $target_label ? ' on ' . $target_label : '' ) . '.', 400 ),
                    'last_error'                 => '',
                )
            );

            return array(
                'success' => true,
                'sent'    => false,
                'queued'  => true,
                'reason'  => isset( $dispatch['reason'] ) ? (string) $dispatch['reason'] : 'queued_actor',
                'actor_id' => isset( $dispatch['actor_id'] ) ? (string) $dispatch['actor_id'] : '',
                'target'  => $target,
            );
        } finally {
            $this->release_daily_report_lock( $report_date );
        }
    }

    public function get_daily_report_state() {
        $state = get_option( Niwa_AI_Constants::OPT_AUTONOMY_REPORT_STATE, array() );
        if ( ! is_array( $state ) ) {
            $state = array();
        }

        return wp_parse_args(
            $state,
            array(
                'last_completed_report_date' => '',
                'last_attempt_report_date'   => '',
                'last_status'                => '',
                'last_reason'                => '',
                'last_sent_at'               => 0,
                'last_attempt_at'            => 0,
                'last_summary'               => '',
                'last_error'                 => '',
            )
        );
    }

    public function run_daily_report_now() {
        return $this->maybe_send_daily_report( true );
    }

    private function get_forced_report_date() {
        $tz  = wp_timezone();
        $now = new DateTimeImmutable( 'now', $tz );
        return array(
            'due'         => true,
            'report_date' => $now->modify( '-1 day' )->format( 'Y-m-d' ),
        );
    }

    private function save_daily_report_state( $state ) {
        update_option(
            Niwa_AI_Constants::OPT_AUTONOMY_REPORT_STATE,
            array(
                'last_completed_report_date' => isset( $state['last_completed_report_date'] ) ? (string) $state['last_completed_report_date'] : '',
                'last_attempt_report_date'   => isset( $state['last_attempt_report_date'] ) ? (string) $state['last_attempt_report_date'] : '',
                'last_status'                => isset( $state['last_status'] ) ? (string) $state['last_status'] : '',
                'last_reason'                => isset( $state['last_reason'] ) ? (string) $state['last_reason'] : '',
                'last_sent_at'               => isset( $state['last_sent_at'] ) ? intval( $state['last_sent_at'] ) : 0,
                'last_attempt_at'            => isset( $state['last_attempt_at'] ) ? intval( $state['last_attempt_at'] ) : 0,
                'last_summary'               => isset( $state['last_summary'] ) ? (string) $state['last_summary'] : '',
                'last_error'                 => isset( $state['last_error'] ) ? (string) $state['last_error'] : '',
            ),
            false
        );
    }

    private function get_due_report_date( $settings ) {
        $tz     = wp_timezone();
        $now    = new DateTimeImmutable( 'now', $tz );
        $run_at = $now->setTime(
            max( 0, min( 23, intval( isset( $settings['daily_report_hour'] ) ? $settings['daily_report_hour'] : 8 ) ) ),
            max( 0, min( 59, intval( isset( $settings['daily_report_minute'] ) ? $settings['daily_report_minute'] : 30 ) ) ),
            0
        );

        if ( $now < $run_at ) {
            return array(
                'due'         => false,
                'report_date' => '',
            );
        }

        return array(
            'due'         => true,
            'report_date' => $now->modify( '-1 day' )->format( 'Y-m-d' ),
        );
    }

    private function should_defer_initial_daily_report( $state, $report_date ) {
        if ( '' === trim( (string) $report_date ) || ! is_array( $state ) ) {
            return false;
        }

        foreach ( array( 'last_completed_report_date', 'last_attempt_report_date', 'last_status', 'last_reason', 'last_summary', 'last_error' ) as $key ) {
            if ( '' !== trim( (string) ( isset( $state[ $key ] ) ? $state[ $key ] : '' ) ) ) {
                return false;
            }
        }

        foreach ( array( 'last_sent_at', 'last_attempt_at' ) as $key ) {
            if ( intval( isset( $state[ $key ] ) ? $state[ $key ] : 0 ) > 0 ) {
                return false;
            }
        }

        return true;
    }

    private function dispatch_daily_report_to_main_agent( $snapshot, $report_date ) {
        $dispatcher = isset( $this->daily_report_dispatcher ) ? $this->daily_report_dispatcher : null;
        if ( ! is_callable( $dispatcher ) ) {
            return array(
                'success' => false,
                'queued'  => false,
                'reason'  => 'daily_report_dispatcher_unavailable',
                'error'   => 'Daily report dispatcher is not configured.',
            );
        }

        $payload = $this->build_daily_report_prompt_payload( $snapshot );
        $payload['report_date'] = '' !== trim( (string) $report_date )
            ? (string) $report_date
            : ( isset( $payload['report_date'] ) ? (string) $payload['report_date'] : '' );

        $result = call_user_func( $dispatcher, $payload );
        return is_array( $result ) ? $result : array(
            'success' => false,
            'queued'  => false,
            'reason'  => 'invalid_dispatcher_result',
            'error'   => 'Daily report dispatcher returned an invalid result.',
        );
    }

    private function get_admin_autonomy_settings() {
        $settings = get_option( Niwa_AI_Constants::OPT_AUTONOMY, array() );
        if ( ! is_array( $settings ) ) {
            $settings = array();
        }

        return wp_parse_args(
            $settings,
            array(
                'enabled'              => 0,
                'owner_chat_id'        => '',
                'daily_report_enabled' => 1,
                'daily_report_hour'    => 8,
                'daily_report_minute'  => 30,
                'founder_notes_seed'   => '',
            )
        );
    }

    private function build_recent_work_notes( $report_date = '' ) {
        $report_date = trim( (string) $report_date );
        if ( ! $this->store || ! method_exists( $this->store, 'list_recent_runs' ) ) {
            return '';
        }

        $site_timezone = wp_timezone();
        $utc           = new DateTimeZone( 'UTC' );
        if ( '' !== $report_date ) {
            try {
                $start_local = new DateTimeImmutable( $report_date . ' 00:00:00', $site_timezone );
            } catch ( Exception ) {
                return '';
            }

            $runs = $this->store->list_recent_runs(
                6,
                $start_local->setTimezone( $utc )->format( 'Y-m-d H:i:s' ),
                $start_local->modify( '+1 day' )->setTimezone( $utc )->format( 'Y-m-d H:i:s' )
            );
        } else {
            $runs = $this->store->list_recent_runs( 6 );
        }
        $lines = array();

        foreach ( (array) $runs as $run ) {
            if ( empty( $run ) || ! is_array( $run ) ) {
                continue;
            }
            $plan    = isset( $run['plan'] ) && is_array( $run['plan'] ) ? $run['plan'] : array();
            $summary = isset( $plan['summary'] ) ? trim( (string) $plan['summary'] ) : '';
            if ( '' === $summary && ! empty( $run['prompt_text'] ) ) {
                $summary = $this->truncate_block( (string) $run['prompt_text'], 120 );
            }
            if ( '' === $summary ) {
                continue;
            }

            $executed_at = isset( $run['executed_at'] )
                ? DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', (string) $run['executed_at'], $utc )
                : false;
            $when = $executed_at ? ' at ' . $executed_at->setTimezone( $site_timezone )->format( DATE_ATOM ) : '';

            $lines[] = '#' . intval( isset( $run['id'] ) ? $run['id'] : 0 ) . ' ' .
                ( isset( $run['execution_state'] ) ? (string) $run['execution_state'] : 'planned' ) . $when . ': ' . $summary;
        }

        return implode( "\n", array_slice( $lines, 0, 5 ) );
    }

    private function build_daily_report_snapshot( $period = 'yesterday' ) {
		$site_profile                         = $this->get_site_operating_profile();
		$snapshot                             = $this->get_metrics_snapshot( $period );
		$snapshot['site_profile']             = $site_profile;
        $snapshot['recent_work']               = $this->build_recent_work_notes( isset( $snapshot['report_date'] ) ? (string) $snapshot['report_date'] : '' );
        $snapshot['recent_customer_questions'] = $this->build_daily_report_question_brief();

		if ( ! empty( $site_profile['catalog_available'] ) ) {
			$snapshot['product_catalog_summary'] = $this->collect_product_catalog_summary();
		} else {
			unset( $snapshot['product_catalog_summary'] );
		}

		if ( ! empty( $site_profile['transactions_available'] ) ) {
			$snapshot['weekly_bestsellers'] = array_slice( (array) $this->collect_weekly_bestsellers(), 0, 5 );
		} else {
			unset( $snapshot['woocommerce'], $snapshot['conversion_busters'], $snapshot['weekly_bestsellers'] );
		}

        return $this->add_daily_report_operational_highlights( $snapshot );
    }

    private function build_daily_report_prompt_payload( $snapshot ) {
		$payload = array(
            'period'                    => isset( $snapshot['period'] ) ? (string) $snapshot['period'] : 'yesterday',
            'period_label'              => isset( $snapshot['period_label'] ) ? (string) $snapshot['period_label'] : 'yesterday',
            'report_date'               => isset( $snapshot['report_date'] ) ? (string) $snapshot['report_date'] : '',
            'host'                      => isset( $snapshot['host'] ) ? (string) $snapshot['host'] : '',
            'site_name'                 => isset( $snapshot['site_name'] ) ? (string) $snapshot['site_name'] : '',
			'site_profile'              => isset( $snapshot['site_profile'] ) && is_array( $snapshot['site_profile'] ) ? $snapshot['site_profile'] : array(),
            'attention_capture'         => $this->prune_metrics_block( isset( $snapshot['attention_capture'] ) ? $snapshot['attention_capture'] : array() ),
            'leads'                     => $this->prune_metrics_block( isset( $snapshot['leads'] ) ? $snapshot['leads'] : array() ),
            'external_analytics'        => $this->prune_metrics_block( isset( $snapshot['external_analytics'] ) ? $snapshot['external_analytics'] : array() ),
            'highlights'                => isset( $snapshot['highlights'] ) ? array_values( (array) $snapshot['highlights'] ) : array(),
            'recent_work'               => isset( $snapshot['recent_work'] ) ? (string) $snapshot['recent_work'] : '',
            'recent_customer_questions' => isset( $snapshot['recent_customer_questions'] ) ? $snapshot['recent_customer_questions'] : array(),
        );

		foreach ( array( 'woocommerce', 'conversion_busters' ) as $key ) {
			if ( isset( $snapshot[ $key ] ) ) {
				$payload[ $key ] = $this->prune_metrics_block( $snapshot[ $key ] );
			}
		}
		if ( isset( $snapshot['product_catalog_summary'] ) ) {
			$payload['product_catalog_summary'] = $snapshot['product_catalog_summary'];
		}
		if ( isset( $snapshot['weekly_bestsellers'] ) ) {
			$payload['weekly_bestsellers'] = array_values( (array) $snapshot['weekly_bestsellers'] );
		}

		return $payload;
    }

    private function add_daily_report_operational_highlights( $snapshot ) {
        $snapshot = is_array( $snapshot ) ? $snapshot : array();
        if ( ! empty( $snapshot['highlights'] ) ) {
            $snapshot['noteworthy'] = true;
            return $snapshot;
        }

        $signals = array();
        if ( ! empty( $snapshot['recent_work'] ) ) {
            $signals[] = 'Recent Niwa work is available for the morning briefing.';
        }

        $questions = isset( $snapshot['recent_customer_questions'] ) && is_array( $snapshot['recent_customer_questions'] ) ? $snapshot['recent_customer_questions'] : array();
        if ( intval( isset( $questions['count_7d'] ) ? $questions['count_7d'] : 0 ) > 0 ) {
            $signals[] = sprintf( '%d recent customer questions are available.', intval( $questions['count_7d'] ) );
        }

        if ( ! empty( $snapshot['weekly_bestsellers'] ) ) {
            $signals[] = 'Weekly bestseller data is available.';
        }

        $catalog = isset( $snapshot['product_catalog_summary'] ) && is_array( $snapshot['product_catalog_summary'] ) ? $snapshot['product_catalog_summary'] : array();
        if ( intval( isset( $catalog['low_stock'] ) ? $catalog['low_stock'] : 0 ) > 0 ) {
            $signals[] = sprintf( '%d published products are low stock.', intval( $catalog['low_stock'] ) );
        }
        if ( intval( isset( $catalog['out_of_stock'] ) ? $catalog['out_of_stock'] : 0 ) > 0 ) {
            $signals[] = sprintf( '%d published products are out of stock.', intval( $catalog['out_of_stock'] ) );
        }

        if ( ! empty( $signals ) ) {
            $snapshot['highlights']  = $signals;
            $snapshot['noteworthy'] = true;
        }

        return $snapshot;
    }

    private function build_daily_report_question_brief() {
        $questions = $this->collect_recent_customer_questions();
        if ( ! is_array( $questions ) ) {
            return array();
        }

        $items = isset( $questions['questions'] ) && is_array( $questions['questions'] ) ? $questions['questions'] : array();
        $top   = array();
        foreach ( array_slice( $items, 0, 3 ) as $row ) {
            if ( ! is_array( $row ) || empty( $row['question'] ) ) {
                continue;
            }
            $top[] = $this->truncate_block( (string) $row['question'], 140 );
        }

        return array(
            'count_7d'      => isset( $questions['count_7d'] ) ? intval( $questions['count_7d'] ) : 0,
            'top_questions' => $top,
            'note'          => isset( $questions['note'] ) ? (string) $questions['note'] : '',
        );
    }

    private function is_daily_report_retry_cooled_down( $state, $report_date ) {
        if ( '' === $report_date || ! is_array( $state ) ) {
            return false;
        }

        $attempt_date = isset( $state['last_attempt_report_date'] ) ? (string) $state['last_attempt_report_date'] : '';
        $status       = isset( $state['last_status'] ) ? (string) $state['last_status'] : '';
        $attempt_at   = intval( isset( $state['last_attempt_at'] ) ? $state['last_attempt_at'] : 0 );
        if ( $attempt_date !== $report_date || $attempt_at <= 0 ) {
            return false;
        }

        if ( ! in_array( $status, array( 'send_failed', 'llm_error', 'actor_enqueue_failed', 'actor_runtime_unavailable', 'daily_report_dispatcher_unavailable', 'missing_delivery_channel' ), true ) ) {
            return false;
        }

        return $attempt_at > ( time() - 10 * MINUTE_IN_SECONDS );
    }

    private function acquire_daily_report_lock( $report_date, $ttl = 300 ) {
        global $wpdb;

        $suffix      = '' !== trim( (string) $report_date ) ? sanitize_key( str_replace( '-', '_', (string) $report_date ) ) : 'current';
        $option_name = 'niwa_ai_admin_autonomy_lock_daily_report_' . $suffix;
        $now         = time();
        $expires     = $now + max( 30, intval( $ttl ) );

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery
        $inserted = $wpdb->query(
            $wpdb->prepare(
                "INSERT IGNORE INTO {$wpdb->options} (option_name, option_value, autoload) VALUES (%s, %s, 'no')",
                $option_name,
                (string) $expires
            )
        );

        if ( $inserted ) {
            wp_cache_delete( $option_name, 'options' );
            return true;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery
        $claimed = $wpdb->query(
            $wpdb->prepare(
                "UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND CAST(option_value AS UNSIGNED) < %d",
                (string) $expires,
                $option_name,
                $now
            )
        );

        if ( $claimed ) {
            wp_cache_delete( $option_name, 'options' );
        }

        return $claimed > 0;
    }

    private function release_daily_report_lock( $report_date ) {
        $suffix      = '' !== trim( (string) $report_date ) ? sanitize_key( str_replace( '-', '_', (string) $report_date ) ) : 'current';
        $option_name = 'niwa_ai_admin_autonomy_lock_daily_report_' . $suffix;
        delete_option( $option_name );
    }
}
