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

add_action( 'admin_post_elementsell_download_billing_invoice', 'elementsell_handle_download_billing_invoice' );

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

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

/**
 * Údaje dodavatele (ElementSell) na faktuře za poplatek.
 *
 * @return array{name: string, address: string, ico: string, dic: string, email: string, web: string}
 */
function elementsell_billing_get_supplier_details() {
    $details = [
        'name'    => 'Petr Kočiš',
        'address' => "Elišky Přemyslovny 434\nPraha 5",
        'ico'     => '14301440',
        'dic'     => '',
        'email'   => elementsell_get_support_email(),
        'web'     => 'elementsell.cz',
    ];

    return apply_filters( 'elementsell_billing_supplier_details', $details );
}

/**
 * @param int $year
 * @param int $month
 * @return array{start: string, end: string, label: string}
 */
function elementsell_billing_get_period_bounds( $year, $month ) {
    $timezone = wp_timezone();
    $start    = new DateTimeImmutable( sprintf( '%04d-%02d-01', $year, $month ), $timezone );
    $end      = $start->modify( 'last day of this month' );

    return [
        'start' => $start->format( 'Y-m-d' ),
        'end'   => $end->format( 'Y-m-d' ),
        'label' => $start->format( 'j. n. Y' ) . ' – ' . $end->format( 'j. n. Y' ),
    ];
}

/**
 * @param int $year
 * @param int $month
 * @return string
 */
function elementsell_billing_get_fee_description( $year, $month ) {
    $bounds = elementsell_billing_get_period_bounds( $year, $month );

    return 'Poplatek za službu ElementSell za období ' . $bounds['label'];
}

/**
 * @param string $payment_uid
 * @return string
 */
function elementsell_billing_generate_invoice_number( $payment_uid ) {
    $year = (string) gmdate( 'Y' );
    $hash = substr( preg_replace( '/[^a-f0-9]/', '', md5( (string) $payment_uid ) ), 0, 14 );

    return $year . $hash;
}

/**
 * @return string|false
 */
function elementsell_billing_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-billing-invoices';

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

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

    return $dir;
}

/**
 * @param int $year
 * @param int $month
 * @return object|null
 */
function elementsell_billing_get_invoice_by_period( $year, $month ) {
    global $wpdb;

    return $wpdb->get_row(
        $wpdb->prepare(
            'SELECT * FROM ' . elementsell_get_billing_invoices_table_name() . ' WHERE billing_year = %d AND billing_month = %d LIMIT 1',
            $year,
            $month
        )
    );
}

/**
 * @return bool
 */
function elementsell_billing_invoices_table_exists() {
    global $wpdb;

    $table = elementsell_get_billing_invoices_table_name();

    return $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) === $table;
}

/**
 * @return void
 */
function elementsell_billing_ensure_tables() {
    if ( ! elementsell_billing_invoices_table_exists() && function_exists( 'elementsell_create_database_tables' ) ) {
        elementsell_create_database_tables();
        update_option( 'elementsell_db_version', defined( 'PF_VERSION' ) ? PF_VERSION : '0' );
    }
}

/**
 * @return int
 */
function elementsell_billing_count_invoices() {
    global $wpdb;

    if ( ! elementsell_billing_invoices_table_exists() ) {
        return 0;
    }

    $table = elementsell_get_billing_invoices_table_name();

    return (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table}" );
}

/**
 * @return int[]
 */
function elementsell_billing_get_invoice_years() {
    global $wpdb;

    if ( ! elementsell_billing_invoices_table_exists() ) {
        return [];
    }

    $table = elementsell_get_billing_invoices_table_name();
    $years = $wpdb->get_col(
        "SELECT DISTINCT billing_year FROM {$table} WHERE billing_year IS NOT NULL AND billing_year > 0 ORDER BY billing_year DESC"
    );

    return array_map( 'intval', (array) $years );
}

/**
 * @param array $args
 * @return array<int, object>
 */
function elementsell_billing_get_invoices_filtered( $args = [] ) {
    global $wpdb;

    elementsell_billing_ensure_tables();

    if ( ! elementsell_billing_invoices_table_exists() ) {
        return [];
    }

    $table = elementsell_get_billing_invoices_table_name();
    $year  = isset( $args['year'] ) ? (int) $args['year'] : 0;
    $month = isset( $args['month'] ) ? (int) $args['month'] : 0;
    $kind  = isset( $args['invoice_kind'] ) ? sanitize_key( (string) $args['invoice_kind'] ) : '';
    $limit = isset( $args['limit'] ) ? max( 1, (int) $args['limit'] ) : 100;

    $where  = [ '1=1' ];
    $params = [];

    if ( $year > 0 ) {
        $where[]  = 'billing_year = %d';
        $params[] = $year;
    }

    if ( $month > 0 ) {
        $where[]  = 'billing_month = %d';
        $params[] = $month;
    }

    if ( $kind !== '' && in_array( $kind, [ 'fee', 'card_verification' ], true ) ) {
        $where[]  = 'invoice_kind = %s';
        $params[] = $kind;
    }

    $sql = "SELECT * FROM {$table} WHERE " . implode( ' AND ', $where ) . " ORDER BY paid_date DESC, id DESC LIMIT {$limit}";

    if ( ! empty( $params ) ) {
        return (array) $wpdb->get_results( $wpdb->prepare( $sql, ...$params ) );
    }

    return (array) $wpdb->get_results( $sql );
}

/**
 * @param array $args
 * @return string
 */
function elementsell_get_billing_invoices_admin_url( $args = [] ) {
    return add_query_arg(
        array_merge(
            [ 'page' => 'elementsell-billing-invoices' ],
            $args
        ),
        admin_url( 'admin.php' )
    );
}

/**
 * @return array<int, object>
 */
function elementsell_billing_get_invoices_list( $limit = 50 ) {
    return elementsell_billing_get_invoices_filtered(
        [
            'limit' => $limit,
        ]
    );
}

/**
 * @param array $args
 * @return int|false
 */
function elementsell_billing_create_invoice( $args ) {
    elementsell_billing_ensure_tables();

    $payment_uid = isset( $args['payment_uid'] ) ? sanitize_text_field( (string) $args['payment_uid'] ) : '';

    if ( $payment_uid === '' ) {
        return false;
    }

    $amount   = isset( $args['amount'] ) ? (float) $args['amount'] : 0.0;
    $currency = isset( $args['currency'] ) ? sanitize_text_field( (string) $args['currency'] ) : 'CZK';
    $year     = isset( $args['billing_year'] ) ? (int) $args['billing_year'] : 0;
    $month    = isset( $args['billing_month'] ) ? (int) $args['billing_month'] : 0;
    $paid_date = isset( $args['paid_date'] ) ? sanitize_text_field( (string) $args['paid_date'] ) : current_time( 'Y-m-d' );

    if ( $year > 0 && $month > 0 ) {
        $existing = elementsell_billing_get_invoice_by_period( $year, $month );

        if ( $existing ) {
            return (int) $existing->id;
        }

        $description  = elementsell_billing_get_fee_description( $year, $month );
        $invoice_kind = 'fee';
    } else {
        $description  = 'Ověření platební karty pro službu ElementSell';
        $invoice_kind = 'card_verification';
    }

    global $wpdb;

    $table          = elementsell_get_billing_invoices_table_name();
    $invoice_number = elementsell_billing_generate_invoice_number( $payment_uid );
    $now            = current_time( 'mysql' );
    $issue_date     = current_time( 'Y-m-d' );

    $row = [
        'invoice_number' => $invoice_number,
        'payment_uid'    => $payment_uid,
        'invoice_kind'   => $invoice_kind,
        'description'    => $description,
        'amount'         => $amount,
        'currency'       => $currency,
        'paid_date'      => $paid_date,
        'issue_date'     => $issue_date,
        'pdf_path'       => null,
        'remote_synced'  => 0,
        'created_at'     => $now,
    ];

    $formats = [ '%s', '%s', '%s', '%s', '%f', '%s', '%s', '%s', '%s', '%d', '%s' ];

    if ( $year > 0 && $month > 0 ) {
        $row['billing_year']  = $year;
        $row['billing_month'] = $month;
        $formats[]            = '%d';
        $formats[]            = '%d';
    } else {
        $row['billing_year']  = null;
        $row['billing_month'] = null;
        $formats[]            = '%s';
        $formats[]            = '%s';
    }

    $inserted = $wpdb->insert( $table, $row, $formats );

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

    $invoice_id = (int) $wpdb->insert_id;
    $pdf_path   = elementsell_billing_generate_invoice_pdf( $invoice_id );

    if ( ! $pdf_path ) {
        error_log( 'ElementSell: PDF faktury za poplatek se nepodařilo vygenerovat (ID ' . $invoice_id . ').' );
    }

    if ( empty( $args['test_only'] ) ) {
        elementsell_billing_sync_invoice_to_remote( $invoice_id );
    }

    if ( class_exists( 'ElementSell_Cron_Log' ) && ElementSell_Cron_Log::is_active() ) {
        ElementSell_Cron_Log::add( 'Faktura za poplatek vystavena (' . $invoice_number . ')' );
    }

    return $invoice_id;
}

/**
 * @param int $invoice_id
 * @return string|false
 */
function elementsell_billing_generate_invoice_pdf( $invoice_id ) {
    global $wpdb;

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

    if ( ! $invoice ) {
        return false;
    }

    if ( ! empty( $invoice->pdf_path ) && file_exists( $invoice->pdf_path ) ) {
        @unlink( $invoice->pdf_path );
    }

    $autoload = dirname( __DIR__, 2 ) . '/vendor_invoice/autoload.php';

    if ( ! file_exists( $autoload ) ) {
        error_log( 'ElementSell: chybí vendor_invoice/autoload.php pro fakturu za poplatek.' );
        return false;
    }

    elementsell_pdf_init_tcpdf();
    require_once $autoload;

    if ( ! class_exists( 'ElementSell_TCPDF', false ) ) {
        class ElementSell_TCPDF extends \TCPDF {
            public function Error( $msg ) {
                throw new Exception( $msg );
            }
        }
    }

    try {
        $supplier = elementsell_billing_get_supplier_details();
        $pdf      = new ElementSell_TCPDF( 'P', 'mm', 'A4', true, 'UTF-8', false );
        $pdf->SetCreator( 'ElementSell' );
        $pdf->SetAuthor( $supplier['name'] );
        $pdf->SetTitle( 'Faktura ' . $invoice->invoice_number );
        $pdf->setPrintHeader( false );
        $pdf->setPrintFooter( false );
        $pdf->SetMargins( 10, 10, 10 );
        $pdf->SetAutoPageBreak( true, 15 );

        $font = elementsell_pdf_get_font_family();
        $pdf->SetFont( $font, '', 12 );
        $pdf->AddPage();

        $logo_path = elementsell_billing_get_supplier_asset_path( 'logo.jpg' );

        if ( ! $logo_path ) {
            $logo_path = elementsell_billing_get_supplier_asset_path( 'logo.png' );
        }

        if ( $logo_path ) {
            $prepared_logo = elementsell_pdf_prepare_image( $logo_path );

            if ( $prepared_logo ) {
                $pdf->Image( $prepared_logo, 10, 12, 0, 22, 'JPEG', '', 'T', false, 300, '', false, false, 0, false, false, false );
            }
        }

        $pdf->SetY( 38 );
        $pdf->writeHTML( elementsell_billing_build_invoice_pdf_html( $invoice ), true, false, true, false, '' );

        $signature_path = elementsell_billing_get_supplier_asset_path( 'signature.jpg' );

        if ( ! $signature_path ) {
            $signature_path = elementsell_billing_get_supplier_asset_path( 'signature.png' );
        }

        if ( $signature_path ) {
            $prepared_signature = elementsell_pdf_prepare_image( $signature_path );

            if ( $prepared_signature ) {
                $signature_y = min( $pdf->GetY() + 6, 250 );
                $pdf->Image( $prepared_signature, 140, $signature_y, 42, 0, 'JPEG', '', 'T', false, 300, '', false, false, 0, false, false, false );
            }
        }

        $upload_dir = elementsell_billing_get_invoice_upload_dir();

        if ( ! $upload_dir ) {
            return false;
        }

        $filename = 'faktura-' . sanitize_file_name( $invoice->invoice_number ) . '.pdf';
        $filepath = trailingslashit( $upload_dir ) . $filename;

        $pdf->Output( $filepath, 'F' );

        if ( ! file_exists( $filepath ) ) {
            return false;
        }

        $wpdb->update(
            elementsell_get_billing_invoices_table_name(),
            [ 'pdf_path' => $filepath ],
            [ 'id' => (int) $invoice->id ],
            [ '%s' ],
            [ '%d' ]
        );

        return $filepath;
    } catch ( Exception $e ) {
        error_log( 'ElementSell: chyba generování PDF faktury za poplatek: ' . $e->getMessage() );
        return false;
    }
}

/**
 * @param string $filename
 * @return string
 */
function elementsell_billing_get_supplier_asset_path( $filename ) {
    $path = PF_PLUGIN_DIR . 'assets/billing/' . $filename;

    return file_exists( $path ) ? $path : '';
}

/**
 * @param object $invoice
 * @return string
 */
function elementsell_billing_build_invoice_pdf_html( $invoice ) {
    $supplier     = elementsell_billing_get_supplier_details();
    $total        = (float) $invoice->amount;
    $paid_date    = mysql2date( 'j. n. Y', $invoice->paid_date, false );
    $invoice_title = 'Faktura č. ' . $invoice->invoice_number;

    $customer_name  = trim( (string) get_option( 'faktury_jmeno', '' ) );
    $customer_addr  = trim( (string) get_option( 'faktury_adresa', '' ) );
    $customer_email = elementsell_get_invoice_supplier_email();
    $customer_ico   = trim( (string) get_option( 'faktury_ico', '' ) );
    $customer_dic   = trim( (string) get_option( 'faktury_dic', '' ) );

    $html  = '<table border="0" cellspacing="0" cellpadding="0" width="100%">';
    $html .= '<tr><td colspan="2" style="border-top: 2px solid #000000; font-size: 1px; line-height: 1px;">&nbsp;</td></tr>';
    $html .= '<tr><td width="55%">&nbsp;</td>';
    $html .= '<td width="45%" align="right" style="font-size: 16pt; font-weight: bold;">' . esc_html( $invoice_title ) . '</td></tr>';
    $html .= '<tr><td width="55%">&nbsp;</td>';
    $html .= '<td width="45%" align="right" style="font-size: 11pt; font-style: italic;">Neplátce DPH</td></tr>';
    $html .= '<tr><td colspan="2" style="border-bottom: 2px solid #000000; font-size: 1px; line-height: 1px; padding-bottom: 8px;">&nbsp;</td></tr>';
    $html .= '</table>';

    $html .= '<table border="0" cellspacing="0" cellpadding="6" width="100%" style="margin-top: 8px;">';
    $html .= '<tr>';
    $html .= '<td width="50%" valign="top"><h3 style="margin: 0 0 8px 0; font-size: 12pt;">Dodavatel</h3>';
    $html .= '<p style="margin: 0 0 4px 0;"><strong>Jméno:</strong> ' . esc_html( $supplier['name'] ) . '</p>';
    $html .= '<p style="margin: 0 0 4px 0;"><strong>Adresa:</strong> ' . nl2br( esc_html( $supplier['address'] ) ) . '</p>';
    $html .= '<p style="margin: 0 0 4px 0;"><strong>E-mail:</strong> ' . esc_html( $supplier['email'] ) . '</p>';
    $html .= '<p style="margin: 0 0 4px 0;"><strong>IČO:</strong> ' . esc_html( $supplier['ico'] ) . '</p>';
    $html .= '<p style="margin: 0 0 4px 0;"><strong>Web:</strong> ' . esc_html( $supplier['web'] ) . '</p>';
    $html .= '</td>';
    $html .= '<td width="50%" valign="top"><h3 style="margin: 0 0 8px 0; font-size: 12pt;">Odběratel</h3>';

    if ( $customer_name !== '' ) {
        $html .= '<p style="margin: 0 0 4px 0;"><strong>Jméno:</strong> ' . esc_html( $customer_name ) . '</p>';
    }

    if ( $customer_addr !== '' ) {
        $html .= '<p style="margin: 0 0 4px 0;"><strong>Adresa:</strong> ' . nl2br( esc_html( $customer_addr ) ) . '</p>';
    }

    if ( $customer_email !== '' ) {
        $html .= '<p style="margin: 0 0 4px 0;"><strong>E-mail:</strong> ' . esc_html( $customer_email ) . '</p>';
    }

    if ( $customer_ico !== '' ) {
        $html .= '<p style="margin: 0 0 4px 0;"><strong>IČO:</strong> ' . esc_html( $customer_ico ) . '</p>';
    }

    if ( $customer_dic !== '' ) {
        $html .= '<p style="margin: 0 0 4px 0;"><strong>DIČ:</strong> ' . esc_html( $customer_dic ) . '</p>';
    }

    $html .= '</td></tr></table>';
    $html .= '<hr style="border: 1px solid #000000; margin: 12px 0;">';

    $html .= '<table border="0" cellspacing="6" cellpadding="4" width="100%">';
    $html .= '<tr>';
    $html .= '<td width="50%" style="font-weight: bold;">Popis</td>';
    $html .= '<td width="50%" align="right" style="font-weight: bold;">Cena</td>';
    $html .= '</tr>';
    $html .= '<tr>';
    $html .= '<td>' . esc_html( $invoice->description ) . '</td>';
    $html .= '<td align="right">' . esc_html( elementsell_format_invoice_amount( $total ) ) . '</td>';
    $html .= '</tr></table>';

    $html .= '<hr style="border: 1px solid #000000; margin: 12px 0;">';
    $html .= '<table border="0" cellspacing="0" cellpadding="4" width="100%">';
    $html .= '<tr>';
    $html .= '<td width="50%">&nbsp;</td>';
    $html .= '<td width="50%" align="right" style="font-size: 14pt; font-weight: bold;">Celkem: ' . esc_html( elementsell_format_invoice_amount( $total ) ) . '</td>';
    $html .= '</tr>';
    $html .= '<tr>';
    $html .= '<td width="50%">&nbsp;</td>';
    $html .= '<td width="50%" align="right" style="font-size: 11pt;">Zaplaceno: ' . esc_html( $paid_date ) . '</td>';
    $html .= '</tr>';
    $html .= '</table>';

    return $html;
}

/**
 * @param int $invoice_id
 * @return bool
 */
function elementsell_billing_sync_invoice_to_remote( $invoice_id ) {
    global $wpdb;

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

    if ( ! $invoice ) {
        return false;
    }

    $pdf_base64 = '';

    if ( ! empty( $invoice->pdf_path ) && file_exists( $invoice->pdf_path ) ) {
        $pdf_base64 = base64_encode( (string) file_get_contents( $invoice->pdf_path ) );
    }

    $supplier = elementsell_billing_get_supplier_details();
    $payload  = [
        'token'           => elementsell_telemetry_get_token(),
        'invoice_kind'    => 'elementsell_fee',
        'invoice_number'  => $invoice->invoice_number,
        'payment_uid'     => $invoice->payment_uid,
        'amount'          => (float) $invoice->amount,
        'currency'        => $invoice->currency,
        'description'     => $invoice->description,
        'paid_date'       => $invoice->paid_date,
        'issue_date'      => $invoice->issue_date,
        'billing_year'    => $invoice->billing_year,
        'billing_month'   => $invoice->billing_month,
        'faktury_jmeno'   => (string) get_option( 'faktury_jmeno', '' ),
        'faktury_adresa'  => (string) get_option( 'faktury_adresa', '' ),
        'faktury_email'   => elementsell_get_invoice_supplier_email(),
        'faktury_ico'     => (string) get_option( 'faktury_ico', '' ),
        'faktury_dic'     => (string) get_option( 'faktury_dic', '' ),
        'web_adresa'      => wp_parse_url( home_url(), PHP_URL_HOST ),
        'site_url'        => get_site_url(),
        'supplier_name'   => $supplier['name'],
        'supplier_email'  => $supplier['email'],
        'pdf_base64'      => $pdf_base64,
    ];

    $remote_url = apply_filters(
        'elementsell_billing_invoice_remote_url',
        'https://elementsell.cz/generate_invoice.php'
    );

    $response = wp_remote_post(
        $remote_url,
        [
            'timeout' => 30,
            'body'    => $payload,
        ]
    );

    if ( is_wp_error( $response ) ) {
        error_log( 'ElementSell: synchronizace faktury na server selhala: ' . $response->get_error_message() );
        return false;
    }

    $code = (int) wp_remote_retrieve_response_code( $response );

    if ( $code < 200 || $code >= 300 ) {
        error_log( 'ElementSell: synchronizace faktury na server vrátila HTTP ' . $code );
        return false;
    }

    $wpdb->update(
        elementsell_get_billing_invoices_table_name(),
        [ 'remote_synced' => 1 ],
        [ 'id' => (int) $invoice->id ],
        [ '%d' ],
        [ '%d' ]
    );

    return true;
}

/**
 * @return void
 */
function elementsell_handle_download_billing_invoice() {
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_die( esc_html__( 'Nemáte oprávnění.', 'platebni-formular' ) );
    }

    $invoice_id = isset( $_GET['invoice_id'] ) ? (int) $_GET['invoice_id'] : 0;

    check_admin_referer( 'elementsell_download_billing_invoice_' . $invoice_id );

    global $wpdb;

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

    if ( ! $invoice || empty( $invoice->pdf_path ) || ! file_exists( $invoice->pdf_path ) ) {
        wp_die( esc_html__( 'Faktura nebyla nalezena.', 'platebni-formular' ) );
    }

    $filename = 'faktura-' . sanitize_file_name( $invoice->invoice_number ) . '.pdf';

    nocache_headers();
    header( 'Content-Type: application/pdf' );
    header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
    header( 'Content-Length: ' . filesize( $invoice->pdf_path ) );
    readfile( $invoice->pdf_path );
    exit;
}

/**
 * @param int $invoice_id
 * @return string
 */
function elementsell_billing_get_invoice_download_url( $invoice_id ) {
    return wp_nonce_url(
        admin_url( 'admin-post.php?action=elementsell_download_billing_invoice&invoice_id=' . (int) $invoice_id ),
        'elementsell_download_billing_invoice_' . (int) $invoice_id
    );
}
