<?php
/**
 * Parcel repository.
 *
 * @package KGV\VereinManager
 */

namespace KGV\VereinManager\Repositories;

use KGV\VereinManager\Schema;

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

class ParcelRepository extends AbstractRepository {

	/**
	 * Resolve table name.
	 *
	 * @return string
	 */
	protected function resolve_table() {
		return Schema::table( 'parcels' );
	}

	/**
	 * Search parcels with relation information.
	 *
	 * @param array $args Query arguments.
	 * @return array
	 */
	public function search( $args = array() ) {
		$search     = isset( $args['s'] ) ? sanitize_text_field( wp_unslash( $args['s'] ) ) : '';
		$status     = isset( $args['status'] ) ? sanitize_key( wp_unslash( $args['status'] ) ) : '';
		$section_id = isset( $args['section_id'] ) ? absint( $args['section_id'] ) : 0;
		$orderby    = $this->sanitize_orderby( isset( $args['orderby'] ) ? sanitize_key( wp_unslash( $args['orderby'] ) ) : 'label', array( 'label', 'status', 'area', 'annual_rent', 'created_at' ), 'label' );
		$order      = $this->sanitize_order( isset( $args['order'] ) ? sanitize_key( wp_unslash( $args['order'] ) ) : 'ASC' );
		$limit      = isset( $args['limit'] ) ? absint( $args['limit'] ) : 0;
		$paged      = isset( $args['paged'] ) ? max( 1, absint( $args['paged'] ) ) : 1;
		$offset     = $limit > 0 ? ( $paged - 1 ) * $limit : 0;

		$meters         = Schema::table( 'meters' );
		$parcel_members = Schema::table( 'parcel_members' );
		$parcel_tenants = Schema::table( 'parcel_tenants' );
		$sections       = Schema::table( 'sections' );

		$sql = "SELECT p.*, s.name AS section_name,
			MAX(CASE WHEN m.type = 'water' THEN m.meter_number ELSE NULL END) AS water_meter_number,
			MAX(CASE WHEN m.type = 'power' THEN m.meter_number ELSE NULL END) AS power_meter_number,
			COUNT(DISTINCT pm.user_id) AS member_count,
			COUNT(DISTINCT pt.tenant_id) AS tenant_count
			FROM {$this->table} p
			LEFT JOIN {$sections} s ON s.id = p.section_id
			LEFT JOIN {$meters} m ON m.parcel_id = p.id
			LEFT JOIN {$parcel_members} pm ON pm.parcel_id = p.id
			LEFT JOIN {$parcel_tenants} pt ON pt.parcel_id = p.id
			WHERE 1=1";

		$params = array();

		if ( '' !== $search ) {
			$like     = '%' . $this->wpdb->esc_like( $search ) . '%';
			$sql     .= ' AND (p.label LIKE %s OR p.note LIKE %s)';
			$params[] = $like;
			$params[] = $like;
		}

		if ( in_array( $status, array( 'free', 'assigned', 'reserved', 'inactive' ), true ) ) {
			$sql     .= ' AND p.status = %s';
			$params[] = $status;
		}

		if ( $section_id > 0 ) {
			$sql     .= ' AND p.section_id = %d';
			$params[] = $section_id;
		}

		$sql .= " GROUP BY p.id ORDER BY p.{$orderby} {$order}, p.id DESC";

		if ( $limit > 0 ) {
			$sql     .= ' LIMIT %d';
			$params[] = $limit;

			if ( $offset > 0 ) {
				$sql     .= ' OFFSET %d';
				$params[] = $offset;
			}
		}

		if ( ! empty( $params ) ) {
			return $this->wpdb->get_results( $this->wpdb->prepare( $sql, $params ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		}

		return $this->wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery
	}

	/**
	 * Count parcels for the current filter set.
	 *
	 * @param array $args Query arguments.
	 * @return int
	 */
	public function count_filtered( $args = array() ) {
		$search     = isset( $args['s'] ) ? sanitize_text_field( wp_unslash( $args['s'] ) ) : '';
		$status     = isset( $args['status'] ) ? sanitize_key( wp_unslash( $args['status'] ) ) : '';
		$section_id = isset( $args['section_id'] ) ? absint( $args['section_id'] ) : 0;
		$sql        = "SELECT COUNT(*) FROM {$this->table} p WHERE 1=1";
		$params     = array();

		if ( '' !== $search ) {
			$like     = '%' . $this->wpdb->esc_like( $search ) . '%';
			$sql     .= ' AND (p.label LIKE %s OR p.note LIKE %s)';
			$params[] = $like;
			$params[] = $like;
		}

		if ( in_array( $status, array( 'free', 'assigned', 'reserved', 'inactive' ), true ) ) {
			$sql     .= ' AND p.status = %s';
			$params[] = $status;
		}

		if ( $section_id > 0 ) {
			$sql     .= ' AND p.section_id = %d';
			$params[] = $section_id;
		}

		if ( ! empty( $params ) ) {
			return (int) $this->wpdb->get_var( $this->wpdb->prepare( $sql, $params ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		}

		return (int) $this->wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery
	}

	/**
	 * Save or update parcel.
	 *
	 * @param array $data Parcel data.
	 * @param int   $id   Optional parcel ID.
	 * @return int|false
	 */
	public function save( $data, $id = 0 ) {
		$payload = array(
			'label'       => $data['label'],
			'section_id'  => $data['section_id'],
			'area'        => $data['area'],
			'annual_rent' => $data['annual_rent'],
			'status'      => $data['status'],
			'note'        => $data['note'],
			'updated_at'  => $this->now(),
		);

		$formats = array( '%s', '%d', '%f', '%f', '%s', '%s', '%s' );

		if ( null === $payload['area'] ) {
			$payload['area'] = null;
			$formats[2]      = '%s';
		}

		if ( null === $payload['annual_rent'] ) {
			$payload['annual_rent'] = null;
			$formats[3]             = '%s';
		}

		if ( $id > 0 ) {
			$this->wpdb->update( $this->table, $payload, array( 'id' => $id ), $formats, array( '%d' ) );
			return $id;
		}

		$payload['created_at'] = $this->now();
		$this->wpdb->insert( $this->table, $payload, array( '%s', '%d', $formats[2], $formats[3], '%s', '%s', '%s', '%s' ) );

		return $this->wpdb->insert_id;
	}

	/**
	 * Check whether a parcel label already exists in the same section.
	 *
	 * @param string $label      Parcel label.
	 * @param int    $section_id Section ID.
	 * @param int    $exclude_id Optional parcel ID.
	 * @return bool
	 */
	public function label_exists( $label, $section_id, $exclude_id = 0 ) {
		$sql    = "SELECT COUNT(*) FROM {$this->table} WHERE label = %s AND section_id = %d";
		$params = array( $label, $section_id );

		if ( $exclude_id > 0 ) {
			$sql      .= ' AND id != %d';
			$params[] = $exclude_id;
		}

		return (int) $this->wpdb->get_var( $this->wpdb->prepare( $sql, $params ) ) > 0; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
	}
}
