<?php
/**
 * Sanitizing and validation helpers.
 *
 * @package KGV\VereinManager
 */

namespace KGV\VereinManager;

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

class Validator {

	/**
	 * Sanitize section input.
	 *
	 * @param array $data Raw request data.
	 * @return array
	 */
	public function sanitize_section( $data ) {
		return array(
			'name'        => sanitize_text_field( wp_unslash( isset( $data['name'] ) ? $data['name'] : '' ) ),
			'description' => sanitize_textarea_field( wp_unslash( isset( $data['description'] ) ? $data['description'] : '' ) ),
			'status'      => sanitize_key( wp_unslash( isset( $data['status'] ) ? $data['status'] : 'active' ) ),
		);
	}

	/**
	 * Validate section.
	 *
	 * @param array $data Sanitized data.
	 * @return \WP_Error
	 */
	public function validate_section( $data ) {
		$errors = new \WP_Error();

		if ( '' === $data['name'] ) {
			$errors->add( 'name_required', __( 'Bitte einen Namen für die Sparte eingeben.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( ! in_array( $data['status'], array( 'active', 'inactive' ), true ) ) {
			$errors->add( 'invalid_status', __( 'Der Status der Sparte ist ungültig.', KGVVM_TEXT_DOMAIN ) );
		}

		return $errors;
	}

	/**
	 * Sanitize parcel input.
	 *
	 * @param array $data Raw request data.
	 * @return array
	 */
	public function sanitize_parcel( $data ) {
		$area        = isset( $data['area'] ) ? str_replace( ',', '.', wp_unslash( $data['area'] ) ) : '';
		$annual_rent = isset( $data['annual_rent'] ) ? str_replace( ',', '.', wp_unslash( $data['annual_rent'] ) ) : '';
		$area        = '' === trim( (string) $area ) ? null : (float) $area;
		$annual_rent = '' === trim( (string) $annual_rent ) ? null : (float) $annual_rent;

		return array(
			'label'       => sanitize_text_field( wp_unslash( isset( $data['label'] ) ? $data['label'] : '' ) ),
			'section_id'  => absint( isset( $data['section_id'] ) ? $data['section_id'] : 0 ),
			'area'        => $area,
			'annual_rent' => $annual_rent,
			'status'      => sanitize_key( wp_unslash( isset( $data['status'] ) ? $data['status'] : 'free' ) ),
			'note'        => sanitize_textarea_field( wp_unslash( isset( $data['note'] ) ? $data['note'] : '' ) ),
		);
	}

	/**
	 * Validate parcel.
	 *
	 * @param array $data Sanitized data.
	 * @return \WP_Error
	 */
	public function validate_parcel( $data ) {
		$errors = new \WP_Error();

		if ( '' === $data['label'] ) {
			$errors->add( 'label_required', __( 'Bitte eine Parzellennummer oder Bezeichnung eingeben.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( $data['section_id'] < 1 ) {
			$errors->add( 'section_required', __( 'Bitte eine Sparte auswählen.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( ! in_array( $data['status'], array( 'free', 'assigned', 'reserved', 'inactive' ), true ) ) {
			$errors->add( 'invalid_status', __( 'Der Parzellenstatus ist ungültig.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( null !== $data['area'] && $data['area'] < 0 ) {
			$errors->add( 'invalid_area', __( 'Die Fläche darf nicht negativ sein.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( null !== $data['annual_rent'] && $data['annual_rent'] < 0 ) {
			$errors->add( 'invalid_annual_rent', __( 'Die Pacht darf nicht negativ sein.', KGVVM_TEXT_DOMAIN ) );
		}

		return $errors;
	}

	/**
	 * Sanitize meter input.
	 *
	 * @param array $data Raw request data.
	 * @return array
	 */
	public function sanitize_meter( $data ) {
		$calibration_year = isset( $data['calibration_year'] ) ? absint( $data['calibration_year'] ) : 0;

		return array(
			'type'             => sanitize_key( wp_unslash( isset( $data['type'] ) ? $data['type'] : '' ) ),
			'meter_number'     => sanitize_text_field( wp_unslash( isset( $data['meter_number'] ) ? $data['meter_number'] : '' ) ),
			'section_id'       => absint( isset( $data['section_id'] ) ? $data['section_id'] : 0 ),
			'installed_at'     => $this->normalize_date( isset( $data['installed_at'] ) ? $data['installed_at'] : '' ),
			'calibration_year' => $calibration_year > 0 ? $calibration_year : null,
			'is_active'        => ! empty( $data['is_active'] ) ? 1 : 0,
			'note'             => sanitize_textarea_field( wp_unslash( isset( $data['note'] ) ? $data['note'] : '' ) ),
		);
	}

	/**
	 * Validate meter data.
	 *
	 * @param array $data Sanitized data.
	 * @return \WP_Error
	 */
	public function validate_meter( $data ) {
		$errors = new \WP_Error();

		if ( ! in_array( $data['type'], array( 'water', 'power' ), true ) ) {
			$errors->add( 'invalid_type', __( 'Bitte einen gültigen Zählertyp auswählen.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( '' === $data['meter_number'] ) {
			$errors->add( 'meter_number_required', __( 'Bitte eine Zählernummer eingeben.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( $data['section_id'] < 1 ) {
			$errors->add( 'section_required', __( 'Bitte eine Sparte für den Zähler auswählen.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( null !== $data['calibration_year'] ) {
			$current_year = (int) gmdate( 'Y' ) + 20;

			if ( $data['calibration_year'] < 2000 || $data['calibration_year'] > $current_year ) {
				$errors->add( 'invalid_calibration_year', __( 'Bitte ein gültiges Eichjahr angeben.', KGVVM_TEXT_DOMAIN ) );
			}
		}

		return $errors;
	}

	/**
	 * Sanitize tenant input.
	 *
	 * @param array $data Raw request data.
	 * @return array
	 */
	public function sanitize_tenant( $data ) {
		return array(
			'first_name'     => sanitize_text_field( wp_unslash( isset( $data['first_name'] ) ? $data['first_name'] : '' ) ),
			'last_name'      => sanitize_text_field( wp_unslash( isset( $data['last_name'] ) ? $data['last_name'] : '' ) ),
			'address'        => sanitize_textarea_field( wp_unslash( isset( $data['address'] ) ? $data['address'] : '' ) ),
			'phone'          => sanitize_text_field( wp_unslash( isset( $data['phone'] ) ? $data['phone'] : '' ) ),
			'email'          => sanitize_email( wp_unslash( isset( $data['email'] ) ? $data['email'] : '' ) ),
			'contract_start' => $this->normalize_date( isset( $data['contract_start'] ) ? $data['contract_start'] : '' ),
			'contract_end'   => $this->normalize_date( isset( $data['contract_end'] ) ? $data['contract_end'] : '' ),
			'is_active'      => ! empty( $data['is_active'] ) ? 1 : 0,
			'note'           => sanitize_textarea_field( wp_unslash( isset( $data['note'] ) ? $data['note'] : '' ) ),
		);
	}

	/**
	 * Validate tenant.
	 *
	 * @param array $data Sanitized data.
	 * @return \WP_Error
	 */
	public function validate_tenant( $data ) {
		$errors = new \WP_Error();

		if ( '' === $data['first_name'] || '' === $data['last_name'] ) {
			$errors->add( 'name_required', __( 'Bitte Vor- und Nachnamen des Pächters angeben.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( '' === $data['contract_start'] ) {
			$errors->add( 'contract_start_required', __( 'Bitte einen Vertragsbeginn angeben.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( $data['email'] && ! is_email( $data['email'] ) ) {
			$errors->add( 'invalid_email', __( 'Die angegebene E-Mail-Adresse ist ungültig.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( $data['contract_start'] && $data['contract_end'] && strtotime( $data['contract_end'] ) < strtotime( $data['contract_start'] ) ) {
			$errors->add( 'invalid_contract_range', __( 'Das Vertragsende darf nicht vor dem Vertragsbeginn liegen.', KGVVM_TEXT_DOMAIN ) );
		}

		return $errors;
	}

	/**
	 * Sanitize meter reading input.
	 *
	 * @param array $data Raw request data.
	 * @return array
	 */
	public function sanitize_meter_reading( $data ) {
		$reading_value = isset( $data['reading_value'] ) ? str_replace( ',', '.', wp_unslash( $data['reading_value'] ) ) : '';

		return array(
			'parcel_id'     => absint( isset( $data['parcel_id'] ) ? $data['parcel_id'] : 0 ),
			'meter_id'      => absint( isset( $data['meter_id'] ) ? $data['meter_id'] : 0 ),
			'reading_value' => '' === trim( (string) $reading_value ) ? '' : (float) $reading_value,
			'reading_date'  => $this->normalize_date( isset( $data['reading_date'] ) ? $data['reading_date'] : '' ),
			'note'          => sanitize_textarea_field( wp_unslash( isset( $data['note'] ) ? $data['note'] : '' ) ),
		);
	}

	/**
	 * Validate one meter reading.
	 *
	 * @param array $data Sanitized data.
	 * @return \WP_Error
	 */
	public function validate_meter_reading( $data ) {
		$errors = new \WP_Error();

		if ( $data['parcel_id'] < 0 ) {
			$errors->add( 'parcel_required', __( 'Die Parzelle für die Ablesung ist ungültig.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( $data['meter_id'] < 1 ) {
			$errors->add( 'meter_required', __( 'Der ausgewählte Zähler ist ungültig.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( '' === $data['reading_date'] ) {
			$errors->add( 'reading_date_required', __( 'Bitte ein Ablesedatum angeben.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( '' === $data['reading_value'] || ! is_numeric( $data['reading_value'] ) ) {
			$errors->add( 'reading_value_required', __( 'Bitte einen gültigen Zählerstand eingeben.', KGVVM_TEXT_DOMAIN ) );
		} elseif ( (float) $data['reading_value'] < 0 ) {
			$errors->add( 'reading_value_negative', __( 'Der Zählerstand darf nicht negativ sein.', KGVVM_TEXT_DOMAIN ) );
		}

		return $errors;
	}

	/**
	 * Sanitize one cost entry.
	 *
	 * @param array $data Raw request data.
	 * @return array
	 */
	public function sanitize_cost_entry( $data ) {
		$unit_amount       = isset( $data['unit_amount'] ) ? str_replace( ',', '.', wp_unslash( $data['unit_amount'] ) ) : '';
		$entry_year        = $this->sanitize_cost_year( $data );
		$distribution_type = sanitize_key( wp_unslash( isset( $data['distribution_type'] ) ? $data['distribution_type'] : 'parcel' ) );
		$is_mandatory      = isset( $data['is_mandatory'] ) && '1' === (string) wp_unslash( $data['is_mandatory'] );

		return array(
			'entry_year'        => $entry_year,
			'name'              => sanitize_text_field( wp_unslash( isset( $data['name'] ) ? $data['name'] : '' ) ),
			'distribution_type' => $distribution_type,
			'unit_amount'       => '' === trim( (string) $unit_amount ) ? '' : (float) $unit_amount,
			'total_cost'        => 0.0,
			'is_mandatory'      => $is_mandatory,
			'note'              => sanitize_textarea_field( wp_unslash( isset( $data['note'] ) ? $data['note'] : '' ) ),
		);
	}

	/**
	 * Validate one cost entry.
	 *
	 * @param array $data Sanitized data.
	 * @return \WP_Error
	 */
	public function validate_cost_entry( $data ) {
		$errors = $this->validate_cost_year( $data['entry_year'] );

		if ( '' === $data['name'] ) {
			$errors->add( 'cost_name_required', __( 'Bitte einen Namen für den Kostenposten eingeben.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( ! in_array( $data['distribution_type'], array( 'parcel', 'member' ), true ) ) {
			$errors->add( 'cost_distribution_required', __( 'Bitte auswählen, ob der Betrag pro Parzelle oder pro Mitglied gilt.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( '' === $data['unit_amount'] || ! is_numeric( $data['unit_amount'] ) ) {
			$errors->add( 'cost_unit_amount_required', __( 'Bitte einen gültigen Betrag eingeben.', KGVVM_TEXT_DOMAIN ) );
		} elseif ( (float) $data['unit_amount'] < 0 ) {
			$errors->add( 'cost_unit_amount_negative', __( 'Der Betrag darf nicht negativ sein.', KGVVM_TEXT_DOMAIN ) );
		}

		return $errors;
	}

	/**
	 * Sanitize the selected cost year.
	 *
	 * @param array $data Raw request data.
	 * @return int
	 */
	public function sanitize_cost_year( $data ) {
		return isset( $data['entry_year'] ) ? absint( $data['entry_year'] ) : 0;
	}

	/**
	 * Sanitize yearly water and electricity prices.
	 *
	 * @param array $data Raw request data.
	 * @return array
	 */
	public function sanitize_cost_year_settings( $data ) {
		$power_price = isset( $data['power_price_per_kwh'] ) ? str_replace( ',', '.', wp_unslash( $data['power_price_per_kwh'] ) ) : '';
		$water_price = isset( $data['water_price_per_m3'] ) ? str_replace( ',', '.', wp_unslash( $data['water_price_per_m3'] ) ) : '';

		return array(
			'entry_year'          => $this->sanitize_cost_year( $data ),
			'section_id'          => absint( isset( $data['section_id'] ) ? $data['section_id'] : 0 ),
			'power_price_per_kwh' => '' === trim( (string) $power_price ) ? null : (float) $power_price,
			'water_price_per_m3'  => '' === trim( (string) $water_price ) ? null : (float) $water_price,
		);
	}

	/**
	 * Validate the selected cost year.
	 *
	 * @param int $entry_year Year value.
	 * @return \WP_Error
	 */
	public function validate_cost_year( $entry_year ) {
		$errors       = new \WP_Error();
		$current_year = (int) gmdate( 'Y' ) + 10;

		if ( $entry_year < 2000 || $entry_year > $current_year ) {
			$errors->add( 'invalid_entry_year', __( 'Bitte ein gültiges Jahr für den Kostenposten auswählen.', KGVVM_TEXT_DOMAIN ) );
		}

		return $errors;
	}

	/**
	 * Validate yearly price settings.
	 *
	 * @param array $data Sanitized year settings.
	 * @return \WP_Error
	 */
	public function validate_cost_year_settings( $data ) {
		$errors = $this->validate_cost_year( $data['entry_year'] );

		if ( $data['section_id'] < 1 ) {
			$errors->add( 'invalid_section', __( 'Bitte eine Sparte auswählen.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( null !== $data['power_price_per_kwh'] && ( ! is_numeric( $data['power_price_per_kwh'] ) || (float) $data['power_price_per_kwh'] < 0 ) ) {
			$errors->add( 'invalid_power_price', __( 'Bitte einen gültigen Preis pro kWh eingeben.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( null !== $data['water_price_per_m3'] && ( ! is_numeric( $data['water_price_per_m3'] ) || (float) $data['water_price_per_m3'] < 0 ) ) {
			$errors->add( 'invalid_water_price', __( 'Bitte einen gültigen Preis pro m³ eingeben.', KGVVM_TEXT_DOMAIN ) );
		}

		return $errors;
	}

	/**
	 * Sanitize one inventory item payload.
	 *
	 * @param array $data Raw request data.
	 * @return array
	 */
	public function sanitize_inventory_item( $data ) {
		return array(
			'name'               => sanitize_text_field( wp_unslash( isset( $data['name'] ) ? $data['name'] : '' ) ),
			'total_quantity'     => absint( isset( $data['total_quantity'] ) ? $data['total_quantity'] : 0 ),
			'available_quantity' => absint( isset( $data['available_quantity'] ) ? $data['available_quantity'] : 0 ),
			'storage_location'   => sanitize_text_field( wp_unslash( isset( $data['storage_location'] ) ? $data['storage_location'] : '' ) ),
			'description'        => sanitize_textarea_field( wp_unslash( isset( $data['description'] ) ? $data['description'] : '' ) ),
			'is_active'          => ! empty( $data['is_active'] ) ? 1 : 0,
		);
	}

	/**
	 * Validate one inventory item payload.
	 *
	 * @param array $data Sanitized data.
	 * @return \WP_Error
	 */
	public function validate_inventory_item( $data ) {
		$errors = new \WP_Error();

		if ( '' === $data['name'] ) {
			$errors->add( 'inventory_name_required', __( 'Bitte einen Namen für den Inventargegenstand eingeben.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( (int) $data['total_quantity'] < 0 ) {
			$errors->add( 'inventory_total_invalid', __( 'Die Gesamtmenge muss 0 oder größer sein.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( (int) $data['available_quantity'] < 0 ) {
			$errors->add( 'inventory_available_invalid', __( 'Die verfügbare Menge muss 0 oder größer sein.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( (int) $data['available_quantity'] > (int) $data['total_quantity'] ) {
			$errors->add( 'inventory_available_too_high', __( 'Die verfügbare Menge darf nicht größer als die Gesamtmenge sein.', KGVVM_TEXT_DOMAIN ) );
		}

		return $errors;
	}

	/**
	 * Sanitize one inventory borrow request.
	 *
	 * @param array $data Raw request data.
	 * @return array
	 */
	public function sanitize_inventory_loan( $data ) {
		return array(
			'item_id'  => absint( isset( $data['item_id'] ) ? $data['item_id'] : 0 ),
			'user_id'  => absint( isset( $data['user_id'] ) ? $data['user_id'] : 0 ),
			'quantity' => absint( isset( $data['quantity'] ) ? $data['quantity'] : 0 ),
			'due_date' => $this->normalize_date( isset( $data['due_date'] ) ? $data['due_date'] : '' ),
			'note'     => sanitize_textarea_field( wp_unslash( isset( $data['note'] ) ? $data['note'] : '' ) ),
		);
	}

	/**
	 * Validate one inventory borrow request.
	 *
	 * @param array $data Sanitized data.
	 * @return \WP_Error
	 */
	public function validate_inventory_loan( $data ) {
		$errors = new \WP_Error();

		if ( (int) $data['item_id'] < 1 ) {
			$errors->add( 'inventory_item_required', __( 'Bitte einen Inventargegenstand auswählen.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( (int) $data['user_id'] < 1 ) {
			$errors->add( 'inventory_user_required', __( 'Bitte ein Mitglied auswählen.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( (int) $data['quantity'] < 1 ) {
			$errors->add( 'inventory_quantity_required', __( 'Bitte eine gültige Ausleihmenge eingeben.', KGVVM_TEXT_DOMAIN ) );
		}

		return $errors;
	}

	/**
	 * Normalize optional date fields to Y-m-d.
	 *
	 * @param string $value Raw value.
	 * @return string|null
	 */
	private function normalize_date( $value ) {
		$value = trim( (string) wp_unslash( $value ) );

		if ( '' === $value ) {
			return '';
		}

		$timestamp = strtotime( $value );

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

		return date( 'Y-m-d', $timestamp );
	}
}
