<?php
/**
 * Business logic for parcel + relations.
 *
 * @package KGV\VereinManager
 */

namespace KGV\VereinManager\Services;

use KGV\VereinManager\Validator;
use KGV\VereinManager\Repositories\AssignmentRepository;
use KGV\VereinManager\Repositories\MeterRepository;
use KGV\VereinManager\Repositories\ParcelRepository;

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

class ParcelService {

	/**
	 * Validator instance.
	 *
	 * @var Validator
	 */
	private $validator;

	/**
	 * Parcel repository.
	 *
	 * @var ParcelRepository
	 */
	private $parcels;

	/**
	 * Meter repository.
	 *
	 * @var MeterRepository
	 */
	private $meters;

	/**
	 * Assignment repository.
	 *
	 * @var AssignmentRepository
	 */
	private $assignments;

	/**
	 * Build service.
	 */
	public function __construct() {
		$this->validator   = new Validator();
		$this->parcels     = new ParcelRepository();
		$this->meters      = new MeterRepository();
		$this->assignments = new AssignmentRepository();
	}

	/**
	 * Save parcel plus relations.
	 *
	 * @param int   $id       Optional parcel ID.
	 * @param array $raw_data Raw submitted data.
	 * @return int|\WP_Error
	 */
	public function save( $id, $raw_data ) {
		$data   = $this->validator->sanitize_parcel( $raw_data );
		$errors = $this->validator->validate_parcel( $data );

		$water_meter_id = absint( isset( $raw_data['water_meter_id'] ) ? $raw_data['water_meter_id'] : 0 );
		$power_meter_id = absint( isset( $raw_data['power_meter_id'] ) ? $raw_data['power_meter_id'] : 0 );
		$member_ids     = array_values( array_unique( array_filter( array_map( 'absint', isset( $raw_data['member_ids'] ) ? (array) wp_unslash( $raw_data['member_ids'] ) : array() ) ) ) );
		$tenant_ids     = array_values( array_unique( array_filter( array_map( 'absint', isset( $raw_data['tenant_ids'] ) ? (array) wp_unslash( $raw_data['tenant_ids'] ) : array() ) ) ) );

		if ( $this->parcels->label_exists( $data['label'], $data['section_id'], $id ) ) {
			$errors->add( 'duplicate_label', __( 'Diese Parzellenbezeichnung existiert in der gewählten Sparte bereits.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( $water_meter_id < 1 ) {
			$errors->add( 'water_meter_required', __( 'Bitte einen freien Wasserzähler auswählen.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( $power_meter_id < 1 ) {
			$errors->add( 'power_meter_required', __( 'Bitte einen freien Stromzähler auswählen.', KGVVM_TEXT_DOMAIN ) );
		}

		$water_meter = $water_meter_id ? $this->meters->get_assignable_meter( $water_meter_id, 'water', $data['section_id'], $id ) : null;
		$power_meter = $power_meter_id ? $this->meters->get_assignable_meter( $power_meter_id, 'power', $data['section_id'], $id ) : null;

		if ( $water_meter_id && ! $water_meter ) {
			$errors->add( 'invalid_water_meter', __( 'Der ausgewählte Wasserzähler ist nicht verfügbar oder gehört zu einer anderen Sparte.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( $power_meter_id && ! $power_meter ) {
			$errors->add( 'invalid_power_meter', __( 'Der ausgewählte Stromzähler ist nicht verfügbar oder gehört zu einer anderen Sparte.', KGVVM_TEXT_DOMAIN ) );
		}

		if ( ! $this->allow_multiple_member_parcels() ) {
			foreach ( $member_ids as $user_id ) {
				if ( $this->assignments->member_has_other_parcels( $user_id, $id ) ) {
					$errors->add( 'member_conflict', __( 'Mindestens ein Mitglied ist bereits einer anderen Parzelle zugeordnet. Die Mehrfachzuordnung ist derzeit deaktiviert.', KGVVM_TEXT_DOMAIN ) );
					break;
				}
			}
		}

		if ( $errors->has_errors() ) {
			return $errors;
		}

		$parcel_id = $this->parcels->save( $data, $id );

		if ( ! $parcel_id ) {
			return new \WP_Error( 'save_failed', __( 'Die Parzelle konnte nicht gespeichert werden.', KGVVM_TEXT_DOMAIN ) );
		}

		$this->meters->release_parcel( $parcel_id );
		$this->meters->assign_to_parcel( $water_meter_id, $parcel_id );
		$this->meters->assign_to_parcel( $power_meter_id, $parcel_id );
		$this->assignments->sync_member_ids( $parcel_id, $member_ids );
		$this->assignments->sync_tenant_ids( $parcel_id, $tenant_ids );

		return $parcel_id;
	}

	/**
	 * Delete a parcel and clean up relations.
	 *
	 * @param int $id Parcel ID.
	 * @return bool
	 */
	public function delete( $id ) {
		$this->meters->release_parcel( $id );
		$this->assignments->purge_parcel( $id );
		return $this->parcels->delete( $id );
	}

	/**
	 * Determine whether a member may own multiple parcels.
	 *
	 * @return bool
	 */
	private function allow_multiple_member_parcels() {
		$settings = get_option( 'kgvvm_settings', array() );
		return ! isset( $settings['allow_multiple_member_parcels'] ) || 1 === (int) $settings['allow_multiple_member_parcels'];
	}
}
