<?php
/**
 * Options and shared helpers.
 */

if ( ! defined( 'ABSPATH' ) ) {
	die;
}

/**
 * Verein settings with defaults. The structured-address fields are separate on
 * purpose: from 15 Nov 2026 (DFÜ-Abkommen Anlage 3, v26.11) SEPA files must
 * carry structured creditor/debtor addresses, so a single free-text address
 * line would leave us unable to produce a valid file.
 */
function bstew_get_options() {
	$defaults = array(
		'verein_name'    => '',
		'street'         => '',
		'postcode'       => '',
		'city'           => '',
		'country'        => 'DE',
		'iban'           => '',
		'bic'            => '',
		'creditor_id'    => '', // Gläubiger-Identifikationsnummer (DE..ZZZ…).
		'default_amount' => '50.00',
		'purpose'        => 'Mitgliedsbeitrag {jahr}',
	);
	$options = get_option( 'bstew_options', array() );
	return wp_parse_args( is_array( $options ) ? $options : array(), $defaults );
}

/** Storage dir for generated XML/PDF, protected from listing. */
function bstew_storage_dir() {
	$upload = wp_upload_dir();
	return trailingslashit( $upload['basedir'] ) . 'beitrag-steward';
}

function bstew_prepare_storage_dir() {
	$dir = bstew_storage_dir();
	if ( ! is_dir( $dir ) ) {
		wp_mkdir_p( $dir );
	}
	// Belt and braces: the files carry bank data, so block direct listing and
	// direct download even on servers that ignore one of the two.
	if ( ! file_exists( $dir . '/index.php' ) ) {
		file_put_contents( $dir . '/index.php', "<?php // Silence is golden.\n" ); // phpcs:ignore
	}
	if ( ! file_exists( $dir . '/.htaccess' ) ) {
		file_put_contents( $dir . '/.htaccess', "Deny from all\n" ); // phpcs:ignore
	}
}

/**
 * IBAN checksum (ISO 13616 mod-97). A single transposed digit in one IBAN
 * makes the bank reject the whole batch, so every stored IBAN passes this.
 */
function bstew_iban_valid( $iban ) {
	$iban = strtoupper( preg_replace( '/\s+/', '', (string) $iban ) );
	if ( ! preg_match( '/^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$/', $iban ) ) {
		return false;
	}
	$moved = substr( $iban, 4 ) . substr( $iban, 0, 4 );
	$expanded = '';
	foreach ( str_split( $moved ) as $ch ) {
		$expanded .= ctype_alpha( $ch ) ? (string) ( ord( $ch ) - 55 ) : $ch;
	}
	// bcmod without bcmath: piecewise mod 97.
	$rest = 0;
	foreach ( str_split( $expanded, 7 ) as $chunk ) {
		$rest = (int) ( ( $rest . $chunk ) % 97 );
	}
	return 1 === $rest;
}

/** Gläubiger-ID format: DE + 2 check digits + business code + 11 alphanumerics. */
function bstew_creditor_id_valid( $id ) {
	$id = strtoupper( preg_replace( '/\s+/', '', (string) $id ) );
	return (bool) preg_match( '/^[A-Z]{2}[0-9]{2}[A-Z0-9]{3}[A-Z0-9]{11}$/', $id );
}

/**
 * Reduce a string to the SEPA character set (EPC best practice). Umlauts are
 * transliterated rather than dropped: "Müller" must arrive as "Mueller", not
 * "Mller", or the member will not recognize the debit on their statement.
 */
function bstew_sepa_text( $text, $maxlen = 70 ) {
	$map  = array(
		'ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'Ä' => 'Ae', 'Ö' => 'Oe', 'Ü' => 'Ue', 'ß' => 'ss',
		'é' => 'e', 'è' => 'e', 'ê' => 'e', 'á' => 'a', 'à' => 'a', 'â' => 'a', 'ç' => 'c',
	);
	$text = strtr( (string) $text, $map );
	// Everything else with a Latin base letter (ı, ł, ñ, ø, š, …) keeps that
	// letter instead of turning into a space and mangling the name.
	if ( function_exists( 'remove_accents' ) ) {
		$text = remove_accents( $text );
	}
	$text = preg_replace( '/[^A-Za-z0-9 \/\-?:().,\'+]/', ' ', $text );
	$text = trim( preg_replace( '/\s+/', ' ', $text ) );
	return mb_substr( $text, 0, $maxlen );
}
