<?php

if ( ! defined( 'ABSPATH' ) ) {

    exit;

}



/**

 * @return string[]

 */

function elementsell_get_unpaid_payment_statuses() {

    return [

        'waiting_for_payment',

        'waiting_for_confirmation',

        'pending',

        'created',

        'payment_created',

    ];

}



/**

 * @param object|null $order

 * @return bool

 */

function elementsell_order_is_unpaid( $order ) {

    if ( ! $order ) {

        return false;

    }



    return in_array( (string) $order->payment_status, elementsell_get_unpaid_payment_statuses(), true );

}



/**

 * @param int $order_id

 * @return int

 */

function elementsell_get_reminder_sent_count( $order_id ) {

    return max( 0, (int) elementsell_get_order_field( (int) $order_id, 'reminder_sent_count' ) );

}



/**

 * Kalendářní dny od objednání (v časovém pásmu webu).

 *

 * @param object     $order

 * @param int|null   $now Unix timestamp, null = teď.

 * @return int

 */

function elementsell_get_days_since_order_created( $order, $now = null ) {

    $timezone = wp_timezone();



    try {

        $created = new DateTimeImmutable( (string) $order->created_at, $timezone );

    } catch ( Exception $e ) {

        return 0;

    }



    if ( null === $now ) {

        $now_dt = new DateTimeImmutable( 'now', $timezone );

    } else {

        $now_dt = ( new DateTimeImmutable( '@' . (int) $now ) )->setTimezone( $timezone );

    }



    $created_midnight = $created->setTime( 0, 0, 0 );

    $now_midnight     = $now_dt->setTime( 0, 0, 0 );



    return (int) $created_midnight->diff( $now_midnight )->days;

}



/**

 * Minuty od objednání — pro první upomínku, která chodí ještě týž den.

 *

 * @param object   $order

 * @param int|null $now Unix timestamp, null = teď.

 * @return int

 */

function elementsell_get_minutes_since_order_created( $order, $now = null ) {

    $timezone = wp_timezone();



    try {

        $created = new DateTimeImmutable( (string) $order->created_at, $timezone );

    } catch ( Exception $e ) {

        return 0;

    }



    $ted = null === $now ? time() : (int) $now;



    return (int) floor( max( 0, $ted - $created->getTimestamp() ) / 60 );

}



/**

 * Za jak dlouho po objednání odejde první upomínka.

 *

 * @return int Minuty.

 */

function elementsell_get_first_reminder_delay_minutes() {

    /**

     * @param int $minuty

     */

    return (int) apply_filters( 'elementsell_first_reminder_delay_minutes', 30 );

}



/**

 * @param object   $order

 * @param int|null $now

 * @return int 0 = nic není splatné, 1–3 = číslo další upomínky

 */

function elementsell_get_reminder_due_number( $order, $now = null ) {

    $sent = elementsell_get_reminder_sent_count( (int) $order->id );



    if ( $sent >= 3 ) {

        return 0;

    }



    $target = $sent + 1;



    // První upomínka jede na minuty — člověk je ještě u počítače.

    if ( 1 === $target ) {

        $minut = elementsell_get_first_reminder_delay_minutes();



        return elementsell_get_minutes_since_order_created( $order, $now ) >= $minut ? 1 : 0;

    }



    // Druhá a třetí zůstávají na kalendářních dnech od objednání.

    return elementsell_get_days_since_order_created( $order, $now ) >= $target ? $target : 0;

}



/**

 * @return string

 */

function elementsell_get_universal_reminder_subject() {

    return 'Nezaplacená objednávka';

}



/**

 * @return string

 */

function elementsell_get_universal_reminder_body() {

    return "Jejda, zjistili jsme, že Vaše objednávka na {product_name} není zaplacena. Byl snad s platbou nějaký problém? Dejte nám vědět.\n\n{sales_page_button}";

}



/**

 * První upomínka — lidský dotaz, žádný nátlak a žádné tlačítko.

 * Druhá a třetí zůstávají na univerzálním znění.

 *

 * @return string

 */

function elementsell_get_first_reminder_body() {

    // Název v uvozovkách schválně — nedá se skloňovat, takhle věta sedí u každého produktu.

    return "{pozdrav}\n\nkoukal jsem, že se ti nepodařilo zaplatit „{product_name}“.\n\nMůžu nějak pomoct?\n\nKrásný den,\n{odesilatel}";

}



/**

 * Znění podle pořadí upomínky.

 *

 * @param int $cislo 1–3

 * @return string

 */

function elementsell_get_reminder_body_for_number( $cislo ) {

    $body = (int) $cislo === 1

        ? elementsell_get_first_reminder_body()

        : elementsell_get_universal_reminder_body();



    /**

     * @param string $body

     * @param int    $cislo

     */

    return (string) apply_filters( 'elementsell_reminder_body', $body, (int) $cislo );

}



/**

 * @param object|null $order

 * @return bool

 */

function elementsell_is_test_order( $order ) {

    return $order && strpos( (string) $order->order_uid, 'test_' ) === 0;

}



/**

 * @param object $order

 * @return bool

 */

function elementsell_email_has_newer_unpaid_order( $order ) {

    global $wpdb;



    $email = strtolower( sanitize_email( (string) $order->email ) );



    if ( $email === '' ) {

        return false;

    }



    $statuses      = elementsell_get_unpaid_payment_statuses();

    $placeholders  = implode( ', ', array_fill( 0, count( $statuses ), '%s' ) );

    $params        = array_merge( [ $email, (int) $order->id, (string) $order->created_at ], $statuses );



    $sql = "SELECT 1

            FROM {$wpdb->prefix}elementsell_orders

            WHERE LOWER(email) = %s

            AND id != %d

            AND created_at > %s

            AND payment_status IN ($placeholders)";



    if ( elementsell_is_test_order( $order ) ) {

        $sql .= " AND order_uid LIKE 'test_%'";

    }



    $sql .= ' LIMIT 1';



    return (bool) $wpdb->get_var( $wpdb->prepare( $sql, $params ) );

}



/**

 * @param object $order

 * @return bool

 */

function elementsell_email_has_paid_order_after( $order ) {

    global $wpdb;



    $email = strtolower( sanitize_email( (string) $order->email ) );



    if ( $email === '' ) {

        return false;

    }



    $sql = "SELECT 1

            FROM {$wpdb->prefix}elementsell_orders

            WHERE LOWER(email) = %s

            AND payment_status = 'paid'

            AND paid_at IS NOT NULL

            AND paid_at > %s";



    if ( elementsell_is_test_order( $order ) ) {

        $sql .= " AND order_uid LIKE 'test_%'";

    }



    $sql .= ' LIMIT 1';



    return (bool) $wpdb->get_var(

        $wpdb->prepare(

            $sql,

            $email,

            (string) $order->created_at

        )

    );

}



/**

 * @param object $order

 * @param bool   $check_schedule

 * @return string

 */

function elementsell_get_reminder_block_reason( $order, $check_schedule = true ) {

    if ( ! $order ) {

        return 'Objednávka neexistuje.';

    }



    if ( elementsell_is_order_payment_paid( $order ) ) {

        return 'Objednávka je už zaplacená.';

    }



    if ( (string) $order->payment_status === 'expired' ) {

        return 'Platba vypršela.';

    }



    if ( ! elementsell_order_is_unpaid( $order ) ) {

        return 'Stav objednávky není vhodný pro upomínku (' . (string) $order->payment_status . ').';

    }



    if ( elementsell_get_reminder_sent_count( (int) $order->id ) >= 3 ) {

        return 'Byly odeslány všechny 3 upomínky.';

    }



    if ( $check_schedule && elementsell_get_reminder_due_number( $order ) === 0 ) {

        $next = elementsell_get_reminder_sent_count( (int) $order->id ) + 1;



        if ( 1 === $next ) {

            return sprintf(

                'Ještě není čas na 1. upomínku (odchází %d minut po objednání, zatím uplynulo %d).',

                elementsell_get_first_reminder_delay_minutes(),

                elementsell_get_minutes_since_order_created( $order )

            );

        }



        return sprintf(

            'Ještě není čas na %d. upomínku (počítáme dny od objednání).',

            $next

        );

    }



    if ( elementsell_email_has_newer_unpaid_order( $order ) ) {

        return 'Zákazník má novější nezaplacenou objednávku — upomínáme jen tu nejnovější.';

    }



    if ( elementsell_email_has_paid_order_after( $order ) ) {

        return 'Zákazník po této objednávce už něco zaplatil — starší nezaplacená objednávka se neupomíná.';

    }



    return '';

}



/**

 * @param object $order

 * @param bool   $ignore_schedule

 * @return bool

 */

function elementsell_should_send_reminder_for_order( $order, $ignore_schedule = false ) {

    return elementsell_get_reminder_block_reason( $order, ! $ignore_schedule ) === '';

}



/**

 * @param object $order

 * @return array{subject: string, body: string}

 */

function elementsell_get_reminder_message_for_order( $order ) {

    $cislo = elementsell_get_reminder_sent_count( (int) $order->id ) + 1;



    $subject = elementsell_get_universal_reminder_subject();

    $body    = elementsell_get_reminder_body_for_number( $cislo );



    $subject = elementsell_replace_email_variables( $subject, $order );

    $body    = elementsell_replace_email_variables( $body, $order );

    $body    = elementsell_replace_email_html_variables( $body, $order );



    return [

        'subject' => $subject,

        'body'    => $body,

    ];

}



/**

 * @param object $order

 * @param bool   $force

 * @return bool|WP_Error

 */

function elementsell_send_order_reminder( $order, $force = false ) {

    $reason = elementsell_get_reminder_block_reason( $order, ! $force );



    if ( $reason !== '' ) {

        return new WP_Error( 'elementsell_reminder_blocked', $reason );

    }



    $message = elementsell_get_reminder_message_for_order( $order );

    $html    = elementsell_email_template(

        $message['subject'],

        elementsell_format_email_body_with_blocks( $message['body'] )

    );



    $from_name = elementsell_get_order_sender_name( (int) $order->id );



    $sent = elementsell_send_email(

        $order->email,

        $message['subject'],

        $html,

        [],

        [],

        $from_name,

        ''

    );



    if ( ! $sent ) {

        $meta  = elementsell_get_last_email_send_meta();

        $error = trim( (string) ( $meta['error'] ?? '' ) );



        elementsell_log_failed_email(

            (int) $order->id,

            $order->email,

            $message['subject'],

            $html

        );



        return new WP_Error(

            'elementsell_reminder_send_failed',

            $error !== '' ? $error : 'E-mail se nepodařilo odeslat.'

        );

    }



    $count = elementsell_get_reminder_sent_count( (int) $order->id ) + 1;



    elementsell_save_order_field( (int) $order->id, 'reminder_sent_count', (string) $count );

    elementsell_save_order_field( (int) $order->id, 'last_reminder_sent_at', current_time( 'mysql' ) );



    elementsell_log_sent_email(

        (int) $order->id,

        $order->email,

        $message['subject'],

        $html

    );



    return true;

}



/**

 * Náhled upomínky — nepočítá se do limitu 3×, chytrá pravidla se neaplikují.

 *

 * @param object      $order

 * @param string|null $to_email

 * @return bool|WP_Error

 */

function elementsell_send_order_reminder_preview( $order, $to_email = null ) {

    if ( ! $order ) {

        return new WP_Error( 'elementsell_reminder_preview', 'Objednávka neexistuje.' );

    }



    if ( null === $to_email || $to_email === '' ) {

        $to_email = sanitize_email( (string) get_option( 'admin_email' ) );

    } else {

        $to_email = sanitize_email( (string) $to_email );

    }



    if ( $to_email === '' || ! is_email( $to_email ) ) {

        return new WP_Error( 'elementsell_reminder_preview', 'Neplatná e-mailová adresa pro náhled.' );

    }



    $message = elementsell_get_reminder_message_for_order( $order );

    $subject = '[Náhled] ' . $message['subject'];

    $html    = elementsell_email_template(

        $subject,

        elementsell_format_email_body_with_blocks( $message['body'] )

    );



    $from_name = elementsell_get_order_sender_name( (int) $order->id );



    $sent = elementsell_send_email(

        $to_email,

        $subject,

        $html,

        [],

        [],

        $from_name,

        ''

    );



    if ( ! $sent ) {

        $meta  = elementsell_get_last_email_send_meta();

        $error = trim( (string) ( $meta['error'] ?? '' ) );



        elementsell_log_failed_email(

            (int) $order->id,

            $to_email,

            $subject,

            $html

        );



        return new WP_Error(

            'elementsell_reminder_preview',

            $error !== '' ? $error : 'E-mail se nepodařilo odeslat.'

        );

    }



    elementsell_log_sent_email(

        (int) $order->id,

        $to_email,

        $subject,

        $html

    );



    return true;

}



/**

 * Posune datum objednávky zpět (simulace stáří pro test upomínek).

 *

 * @param int $order_id

 * @param int $days Kolik dní přidat ke stáří (1 = objednávka o den starší).

 * @return bool|WP_Error

 */

function elementsell_shift_order_created_date( $order_id, $days = 1 ) {

    global $wpdb;



    $order_id = (int) $order_id;

    $days     = max( 1, (int) $days );

    $order    = elementsell_get_order( $order_id );



    if ( ! $order ) {

        return new WP_Error( 'elementsell_reminder_age', 'Objednávka neexistuje.' );

    }



    $timezone = wp_timezone();



    try {

        $created = new DateTimeImmutable( (string) $order->created_at, $timezone );

    } catch ( Exception $e ) {

        return new WP_Error( 'elementsell_reminder_age', 'Neplatné datum objednávky.' );

    }



    $new_created = $created->sub( new DateInterval( 'P' . $days . 'D' ) );



    $wpdb->update(

        $wpdb->prefix . 'elementsell_orders',

        [

            'created_at' => $new_created->format( 'Y-m-d H:i:s' ),

            'updated_at' => current_time( 'mysql' ),

        ],

        [ 'id' => $order_id ],

        [ '%s', '%s' ],

        [ '%d' ]

    );



    return true;

}



/**

 * @param array{force_order_id?: int, dry_run?: bool, test_only?: bool, test_email?: string} $args

 * @return array{checked: int, sent: int, skipped: int, errors: string[], sent_ids: int[]}

 */

function elementsell_process_payment_reminders( $args = [] ) {

    global $wpdb;



    $force_order_id = isset( $args['force_order_id'] ) ? (int) $args['force_order_id'] : 0;

    $dry_run        = ! empty( $args['dry_run'] );

    $test_only      = ! empty( $args['test_only'] );

    $test_email     = isset( $args['test_email'] ) ? sanitize_email( (string) $args['test_email'] ) : '';

    $result         = [

        'checked'   => 0,

        'sent'      => 0,

        'skipped'   => 0,

        'errors'    => [],

        'sent_ids'  => [],

    ];



    if ( $force_order_id > 0 ) {

        $orders = [ elementsell_get_order( $force_order_id ) ];

    } else {

        $statuses     = elementsell_get_unpaid_payment_statuses();

        $placeholders = implode( ', ', array_fill( 0, count( $statuses ), '%s' ) );



        if ( $test_only ) {

            if ( $test_email === '' ) {

                $orders = [];

            } else {

                $params = array_merge( [ $test_email ], $statuses );



                $orders = $wpdb->get_results(

                    $wpdb->prepare(

                        "SELECT * FROM {$wpdb->prefix}elementsell_orders

                         WHERE LOWER(email) = LOWER(%s)

                         AND order_uid LIKE 'test_%'

                         AND payment_status IN ($placeholders)

                         ORDER BY created_at ASC",

                        $params

                    )

                );

            }

        } else {

            $orders = $wpdb->get_results(

                $wpdb->prepare(

                    "SELECT * FROM {$wpdb->prefix}elementsell_orders

                     WHERE payment_status IN ($placeholders)

                     ORDER BY created_at ASC",

                    $statuses

                )

            );

        }

    }



    foreach ( (array) $orders as $order ) {

        if ( ! $order ) {

            continue;

        }



        ++$result['checked'];



        if ( elementsell_get_reminder_block_reason( $order, $force_order_id <= 0 ) !== '' ) {

            ++$result['skipped'];

            continue;

        }



        if ( $dry_run ) {

            ++$result['sent'];

            $result['sent_ids'][] = (int) $order->id;

            continue;

        }



        $send = elementsell_send_order_reminder( $order, $force_order_id > 0 );



        if ( is_wp_error( $send ) ) {

            $result['errors'][] = 'Objednávka #' . (int) $order->id . ': ' . $send->get_error_message();

            ++$result['skipped'];

            continue;

        }



        ++$result['sent'];

        $result['sent_ids'][] = (int) $order->id;

    }



    return $result;

}

