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

/**
 * @return string
 */
function elementsell_get_invoices_table_name() {
    global $wpdb;

    return $wpdb->prefix . 'elementsell_invoices';
}

/**
 * @param int $invoice_id
 * @return object|null
 */
function elementsell_get_invoice( $invoice_id ) {
    global $wpdb;

    $invoice = $wpdb->get_row(
        $wpdb->prepare(
            'SELECT * FROM ' . elementsell_get_invoices_table_name() . ' WHERE id = %d',
            $invoice_id
        )
    );

    if ( $invoice || ! function_exists( 'elementsell_orders_archive_table_exists' ) || ! elementsell_orders_archive_table_exists() ) {
        return $invoice;
    }

    return $wpdb->get_row(
        $wpdb->prepare(
            'SELECT * FROM ' . elementsell_get_invoices_archive_table_name() . ' WHERE id = %d',
            $invoice_id
        )
    );
}

/**
 * @param int $order_id
 * @return object|null
 */
function elementsell_get_invoice_by_order_id( $order_id ) {
    global $wpdb;

    $invoice = $wpdb->get_row(
        $wpdb->prepare(
            'SELECT * FROM ' . elementsell_get_invoices_table_name() . ' WHERE order_id = %d LIMIT 1',
            $order_id
        )
    );

    if ( $invoice || ! function_exists( 'elementsell_orders_archive_table_exists' ) || ! elementsell_orders_archive_table_exists() ) {
        return $invoice;
    }

    return $wpdb->get_row(
        $wpdb->prepare(
            'SELECT * FROM ' . elementsell_get_invoices_archive_table_name() . ' WHERE order_id = %d LIMIT 1',
            $order_id
        )
    );
}

/**
 * @param array $order_ids
 * @return array<int, object> Klíč order_id, hodnota faktura.
 */
function elementsell_get_invoices_by_order_ids( $order_ids ) {
    global $wpdb;

    $order_ids = array_filter( array_map( 'intval', (array) $order_ids ) );

    if ( empty( $order_ids ) ) {
        return [];
    }

    $placeholders = implode( ', ', array_fill( 0, count( $order_ids ), '%d' ) );
    $table        = elementsell_get_invoices_table_name();

    $rows = $wpdb->get_results(
        $wpdb->prepare(
            "SELECT * FROM {$table} WHERE order_id IN ({$placeholders})",
            ...$order_ids
        )
    );

    $invoices = [];

    foreach ( (array) $rows as $row ) {
        $invoices[ (int) $row->order_id ] = $row;
    }

    return $invoices;
}

/**
 * @param object|int $order
 * @return string
 */
function elementsell_generate_demo_invoice_number( $order ) {
    if ( ! is_object( $order ) ) {
        $order = elementsell_get_order( $order );
    }

    $year = (string) (int) current_time( 'Y' );

    return 'DEMO-' . $year . str_pad( (string) (int) $order->id, 4, '0', STR_PAD_LEFT );
}

/**
 * @param object|null $order
 * @return string
 */
function elementsell_generate_next_invoice_number( $order = null ) {
    if ( $order && elementsell_is_demo_order( $order ) ) {
        return elementsell_generate_demo_invoice_number( $order );
    }

    global $wpdb;

    $table = elementsell_get_invoices_table_name();
    $year  = (string) (int) current_time( 'Y' );

    $max_number = $wpdb->get_var(
        $wpdb->prepare(
            "SELECT invoice_number FROM {$table} WHERE invoice_number NOT LIKE %s AND invoice_number LIKE %s ORDER BY invoice_number DESC LIMIT 1",
            'DEMO-%',
            $year . '%'
        )
    );

    if ( $max_number && strpos( $max_number, $year ) === 0 ) {
        $sequence = (int) substr( $max_number, 4 ) + 1;
    } else {
        $sequence = 1;
    }

    return $year . str_pad( (string) $sequence, 5, '0', STR_PAD_LEFT );
}

/**
 * @param object|int $order
 * @return bool
 */
function elementsell_is_demo_order( $order ) {
    if ( ! is_object( $order ) ) {
        $order = elementsell_get_order( $order );
    }

    if ( ! $order ) {
        return false;
    }

    $order_id = (int) $order->id;

    if ( elementsell_get_order_field( $order_id, 'environment' ) === 'demo' ) {
        return true;
    }

    if ( elementsell_get_order_field( $order_id, 'landing_demo' ) === '1' ) {
        return true;
    }

    $api_url  = (string) elementsell_get_order_field( $order_id, 'api_url' );
    $gate_url = (string) elementsell_get_order_field( $order_id, 'gate_url' );
    $urls     = $api_url . ' ' . $gate_url;

    return $urls !== ' ' && strpos( $urls, 'demo.' ) !== false;
}

/**
 * @param object|int $order
 * @return bool
 */
function elementsell_is_order_paid( $order ) {
    if ( ! is_object( $order ) ) {
        $order = elementsell_get_order( $order );
    }

    if ( ! $order ) {
        return false;
    }

    return $order->payment_status === 'paid';
}

/**
 * @param object $order
 * @return string|null
 */
function elementsell_get_invoice_paid_date_for_order( $order ) {
    if ( ! empty( $order->paid_at ) ) {
        return mysql2date( 'Y-m-d', $order->paid_at, false );
    }

    return current_time( 'Y-m-d' );
}

/**
 * Určí typ, stav a datum úhrady faktury podle objednávky.
 *
 * @param object|int $order
 * @return array{type: string, status: string, paid_date: string|null}
 */
function elementsell_resolve_invoice_state_for_order( $order ) {
    if ( ! is_object( $order ) ) {
        $order = elementsell_get_order( $order );
    }

    if ( ! $order ) {
        return [
            'type'      => 'invoice',
            'status'    => 'unpaid',
            'paid_date' => null,
        ];
    }

    if ( elementsell_is_demo_order( $order ) ) {
        return [
            'type'      => 'demo',
            'status'    => elementsell_is_order_paid( $order ) ? 'paid' : 'unpaid',
            'paid_date' => elementsell_is_order_paid( $order ) ? elementsell_get_invoice_paid_date_for_order( $order ) : null,
        ];
    }

    if ( elementsell_is_order_paid( $order ) ) {
        return [
            'type'      => 'invoice',
            'status'    => 'paid',
            'paid_date' => elementsell_get_invoice_paid_date_for_order( $order ),
        ];
    }

    return [
        'type'      => 'invoice',
        'status'    => 'unpaid',
        'paid_date' => null,
    ];
}

/**
 * Doplní environment=demo u starších objednávek podle demo API URL.
 *
 * @param object $order
 * @return void
 */
function elementsell_backfill_demo_environment_for_order( $order ) {
    if ( ! $order ) {
        return;
    }

    $order_id = (int) $order->id;

    if ( elementsell_get_order_field( $order_id, 'environment' ) !== '' ) {
        return;
    }

    $api_url = (string) elementsell_get_order_field( $order_id, 'api_url' );

    if ( $api_url !== '' && strpos( $api_url, 'demo.' ) !== false ) {
        elementsell_save_order_field( $order_id, 'environment', 'demo' );
    }
}

/**
 * Synchronizuje existující fakturu s aktuálním stavem objednávky.
 *
 * @param int $order_id
 * @return int|false|int|null
 */
function elementsell_sync_invoice_with_order( $order_id ) {
    $order_id = intval( $order_id );

    if ( $order_id <= 0 ) {
        return false;
    }

    $order = elementsell_get_order( $order_id );

    if ( ! $order ) {
        return false;
    }

    $invoice = elementsell_get_invoice_by_order_id( $order_id );

    if ( ! $invoice ) {
        return elementsell_create_invoice_for_order( $order_id );
    }

    elementsell_backfill_demo_environment_for_order( $order );

    $state = elementsell_resolve_invoice_state_for_order( $order );

    global $wpdb;

    $update_data = [
        'type'       => $state['type'],
        'status'     => $state['status'],
        'paid_date'  => $state['paid_date'],
        'updated_at' => current_time( 'mysql' ),
    ];

    if ( $state['type'] === 'demo' && strpos( (string) $invoice->invoice_number, 'DEMO-' ) !== 0 ) {
        $update_data['invoice_number'] = elementsell_generate_demo_invoice_number( $order );
    }

    if ( $state['type'] === 'invoice' && strpos( (string) $invoice->invoice_number, 'DEMO-' ) === 0 ) {
        $update_data['invoice_number'] = elementsell_generate_next_invoice_number( null );
    }

    return $wpdb->update(
        elementsell_get_invoices_table_name(),
        $update_data,
        [ 'id' => (int) $invoice->id ],
        array_fill( 0, count( $update_data ), '%s' ),
        [ '%d' ]
    );
}

/**
 * Vytvoří fakturu pro objednávku, pokud ještě neexistuje.
 *
 * @param int $order_id
 * @return int|false ID faktury nebo false při chybě / duplicitě.
 */
function elementsell_create_invoice_for_order( $order_id ) {
    $order_id = intval( $order_id );

    if ( $order_id <= 0 ) {
        return false;
    }

    if ( elementsell_get_invoice_by_order_id( $order_id ) ) {
        return false;
    }

    $order = elementsell_get_order( $order_id );

    if ( ! $order ) {
        return false;
    }

    elementsell_backfill_demo_environment_for_order( $order );

    $now = current_time( 'mysql' );

    $vat_rate = 0.0;

    if ( function_exists( 'elementsell_is_invoice_vat_payer' ) && elementsell_is_invoice_vat_payer() ) {
        $vat_rate = function_exists( 'elementsell_get_invoice_vat_rate' )
            ? elementsell_get_invoice_vat_rate()
            : 0.0;
    }

    $state = elementsell_resolve_invoice_state_for_order( $order );

    global $wpdb;

    $invoice_data = [
        'order_id'       => $order_id,
        'invoice_number' => elementsell_generate_next_invoice_number( $order ),
        'type'           => $state['type'],
        'status'         => $state['status'],
        'issue_date'     => current_time( 'Y-m-d' ),
        'due_date'       => null,
        'paid_date'      => $state['paid_date'],
        'product_name'   => elementsell_get_invoice_product_description_for_order( $order ),
        'price'          => $order->amount,
        'vat_rate'       => $vat_rate,
        'pdf_path'       => null,
        'created_at'     => $now,
        'updated_at'     => $now,
    ];

    $inserted = $wpdb->insert( elementsell_get_invoices_table_name(), $invoice_data );

    if ( false === $inserted ) {
        error_log( 'ElementSell: chyba uložení faktury: ' . $wpdb->last_error );
        return false;
    }

    return (int) $wpdb->insert_id;
}

/**
 * @param int $invoice_id
 * @return string
 */
function elementsell_get_invoice_admin_url( $invoice_id ) {
    return admin_url( 'admin.php?page=elementsell-invoice&invoice_id=' . intval( $invoice_id ) );
}

/**
 * @param int    $invoice_id
 * @param string $return
 * @return string
 */
function elementsell_get_invoice_edit_admin_url( $invoice_id, $return = 'issued' ) {
    return add_query_arg(
        [
            'page'       => 'elementsell-invoice-edit',
            'invoice_id' => (int) $invoice_id,
            'return'     => sanitize_key( (string) $return ),
        ],
        admin_url( 'admin.php' )
    );
}

/**
 * @param int   $invoice_id
 * @param array $data
 * @return true|WP_Error
 */
function elementsell_update_issued_invoice( $invoice_id, $data ) {
    $invoice_id = (int) $invoice_id;
    $invoice    = elementsell_get_invoice( $invoice_id );

    if ( ! $invoice ) {
        return new WP_Error( 'missing_invoice', 'Faktura nebyla nalezena.' );
    }

    if ( (string) $invoice->type === 'demo' ) {
        return new WP_Error( 'demo_invoice', 'DEMO fakturu nelze upravit.' );
    }

    $order = elementsell_get_order( (int) $invoice->order_id );

    if ( ! $order ) {
        return new WP_Error( 'missing_order', 'Objednávka k faktuře nebyla nalezena.' );
    }

    $product_name = isset( $data['product_name'] ) ? sanitize_text_field( (string) $data['product_name'] ) : (string) $invoice->product_name;
    $price        = isset( $data['price'] ) ? (float) $data['price'] : (float) $invoice->price;
    $issue_date   = isset( $data['issue_date'] ) ? sanitize_text_field( (string) $data['issue_date'] ) : (string) $invoice->issue_date;
    $paid_date    = isset( $data['paid_date'] ) ? sanitize_text_field( (string) $data['paid_date'] ) : (string) $invoice->paid_date;
    $first_name   = isset( $data['first_name'] ) ? sanitize_text_field( (string) $data['first_name'] ) : (string) $order->first_name;
    $surname      = isset( $data['surname'] ) ? sanitize_text_field( (string) $data['surname'] ) : (string) $order->surname;
    $company      = isset( $data['company'] ) ? sanitize_text_field( (string) $data['company'] ) : (string) elementsell_get_order_field( $order->id, 'company' );
    $address      = isset( $data['address'] ) ? sanitize_textarea_field( (string) $data['address'] ) : (string) elementsell_get_order_field( $order->id, 'address' );
    $ico          = isset( $data['ico'] ) ? sanitize_text_field( (string) $data['ico'] ) : (string) elementsell_get_order_field( $order->id, 'ico' );
    $dic          = isset( $data['dic'] ) ? sanitize_text_field( (string) $data['dic'] ) : (string) elementsell_get_order_field( $order->id, 'dic' );

    if ( $product_name === '' ) {
        return new WP_Error( 'invalid_product_name', 'Popis na faktuře nesmí být prázdný.' );
    }

    if ( $price <= 0 ) {
        return new WP_Error( 'invalid_price', 'Částka musí být větší než 0.' );
    }

    if ( ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $issue_date ) || ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $paid_date ) ) {
        return new WP_Error( 'invalid_date', 'Datum musí být ve formátu RRRR-MM-DD.' );
    }

    global $wpdb;

    $invoice_updated = $wpdb->update(
        elementsell_get_invoices_storage_table_for_id( $invoice_id ),
        [
            'product_name' => $product_name,
            'price'        => $price,
            'issue_date'   => $issue_date,
            'paid_date'    => $paid_date,
            'updated_at'   => current_time( 'mysql' ),
        ],
        [ 'id' => $invoice_id ],
        [ '%s', '%f', '%s', '%s', '%s' ],
        [ '%d' ]
    );

    if ( false === $invoice_updated ) {
        return new WP_Error( 'db_error', 'Fakturu se nepodařilo uložit.' );
    }

    elementsell_update_order(
        (int) $order->id,
        [
            'first_name' => $first_name,
            'surname'    => $surname,
            'amount'     => $price,
            'updated_at' => current_time( 'mysql' ),
        ]
    );

    if ( function_exists( 'elementsell_upsert_order_field' ) ) {
        elementsell_upsert_order_field( (int) $order->id, 'company', $company );
        elementsell_upsert_order_field( (int) $order->id, 'address', $address );
        elementsell_upsert_order_field( (int) $order->id, 'ico', $ico );
        elementsell_upsert_order_field( (int) $order->id, 'dic', $dic );
    }

    if ( function_exists( 'elementsell_generate_invoice_pdf_file' ) ) {
        $pdf_path = elementsell_generate_invoice_pdf_file( $invoice_id );

        if ( ! $pdf_path ) {
            return new WP_Error( 'pdf_error', 'Faktura byla uložena, ale PDF se nepodařilo přegenerovat.' );
        }
    }

    return true;
}

/**
 * @param float $amount
 * @return string
 */
function elementsell_format_invoice_amount( $amount ) {
    return number_format( (float) $amount, 2, ',', ' ' ) . ' Kč';
}

/**
 * E-mail dodavatele na faktuře — Gmail z administrace, jinak dříve uložený faktury_email.
 *
 * @return string
 */
function elementsell_get_invoice_supplier_email() {
    $gmail = sanitize_email( (string) get_option( 'elementsell_gmail_address', '' ) );

    if ( $gmail !== '' && is_email( $gmail ) ) {
        return $gmail;
    }

    $legacy = sanitize_email( (string) get_option( 'faktury_email', '' ) );

    if ( $legacy !== '' && is_email( $legacy ) ) {
        return $legacy;
    }

    return '';
}

/**
 * Web dodavatele na faktuře — z WordPress URL bez protokolu.
 *
 * @return string
 */
function elementsell_get_invoice_supplier_web() {
    $site_url = (string) get_option( 'siteurl', '' );

    if ( $site_url === '' ) {
        $site_url = home_url();
    }

    $host = wp_parse_url( $site_url, PHP_URL_HOST );

    if ( is_string( $host ) && $host !== '' ) {
        return $host;
    }

    $web = preg_replace( '#^https?://#i', '', $site_url );
    $web = rtrim( (string) $web, '/' );

    return $web;
}

/**
 * @return string
 */
function elementsell_get_invoice_upload_dir() {
    $upload = wp_upload_dir();

    if ( ! empty( $upload['error'] ) ) {
        error_log( 'ElementSell: upload dir chyba: ' . $upload['error'] );
        return false;
    }

    $dir = trailingslashit( $upload['basedir'] ) . 'elementsell-invoices';

    if ( ! file_exists( $dir ) ) {
        wp_mkdir_p( $dir );
    }

    if ( ! is_writable( $dir ) ) {
        error_log( 'ElementSell: složka pro faktury není zapisovatelná: ' . $dir );
        return false;
    }

    return $dir;
}
