<?php
/**
 * Database schema management.
 *
 * @package KGV\VereinManager
 */

namespace KGV\VereinManager;

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

class Schema {

	/**
	 * Get the full table name by key.
	 *
	 * @param string $key Table key.
	 * @return string
	 */
	public static function table( $key ) {
		global $wpdb;

		$map = array(
			'sections'       => $wpdb->prefix . 'kgvvm_sections',
			'parcels'        => $wpdb->prefix . 'kgvvm_parcels',
			'meters'         => $wpdb->prefix . 'kgvvm_meters',
			'tenants'        => $wpdb->prefix . 'kgvvm_tenants',
			'inventory_items' => $wpdb->prefix . 'kgvvm_inventory_items',
			'inventory_loans' => $wpdb->prefix . 'kgvvm_inventory_loans',
			'parcel_members' => $wpdb->prefix . 'kgvvm_parcel_members',
			'parcel_tenants' => $wpdb->prefix . 'kgvvm_parcel_tenants',
			'chat_messages'  => $wpdb->prefix . 'kgvvm_chat_messages',
			'meter_readings' => $wpdb->prefix . 'kgvvm_meter_readings',
			'cost_years'     => $wpdb->prefix . 'kgvvm_cost_years',
			'cost_rates'     => $wpdb->prefix . 'kgvvm_cost_rates',
			'cost_entries'      => $wpdb->prefix . 'kgvvm_cost_entries',
			'work_jobs'         => $wpdb->prefix . 'kgvvm_work_jobs',
			'work_year_config'  => $wpdb->prefix . 'kgvvm_work_year_config',
'work_logs'              => $wpdb->prefix . 'kgvvm_work_logs',
			'work_log_members'       => $wpdb->prefix . 'kgvvm_work_log_members',
			'parcel_cost_assignments' => $wpdb->prefix . 'kgvvm_parcel_cost_assignments',
		);

		return isset( $map[ $key ] ) ? $map[ $key ] : '';
	}

	/**
	 * Create plugin tables.
	 *
	 * @return void
	 */
	public static function create_tables() {
		global $wpdb;

		require_once ABSPATH . 'wp-admin/includes/upgrade.php';

		$charset_collate = $wpdb->get_charset_collate();

		$sql = array();

		$sql[] = "CREATE TABLE " . self::table( 'sections' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			name VARCHAR(190) NOT NULL,
			description TEXT NULL,
			status VARCHAR(20) NOT NULL DEFAULT 'active',
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			UNIQUE KEY name (name),
			KEY status (status)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'parcels' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			label VARCHAR(100) NOT NULL,
			section_id BIGINT UNSIGNED NOT NULL,
			area DECIMAL(10,2) NULL,
			annual_rent DECIMAL(12,2) NULL,
			status VARCHAR(20) NOT NULL DEFAULT 'free',
			note TEXT NULL,
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			UNIQUE KEY section_label (section_id, label),
			KEY status (status),
			KEY section_id (section_id)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'meters' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			type VARCHAR(20) NOT NULL,
			meter_number VARCHAR(100) NOT NULL,
			section_id BIGINT UNSIGNED NOT NULL,
			parcel_id BIGINT UNSIGNED NULL,
			installed_at DATE NULL,
			calibration_year SMALLINT UNSIGNED NULL,
			is_main_meter TINYINT(1) NOT NULL DEFAULT 0,
			is_active TINYINT(1) NOT NULL DEFAULT 1,
			note TEXT NULL,
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			UNIQUE KEY type_meter_number (type, meter_number),
			KEY section_id (section_id),
			KEY parcel_id (parcel_id),
			KEY type (type),
			KEY is_main_meter (is_main_meter),
			KEY is_active (is_active)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'tenants' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			first_name VARCHAR(100) NOT NULL,
			last_name VARCHAR(100) NOT NULL,
			address TEXT NULL,
			phone VARCHAR(100) NULL,
			email VARCHAR(190) NULL,
			contract_start DATE NOT NULL,
			contract_end DATE NULL,
			is_active TINYINT(1) NOT NULL DEFAULT 1,
			note TEXT NULL,
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			KEY name_lookup (last_name, first_name),
			KEY is_active (is_active)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'inventory_items' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			name VARCHAR(190) NOT NULL,
			total_quantity INT UNSIGNED NOT NULL DEFAULT 0,
			available_quantity INT UNSIGNED NOT NULL DEFAULT 0,
			storage_location VARCHAR(190) NULL,
			description TEXT NULL,
			is_active TINYINT(1) NOT NULL DEFAULT 1,
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			KEY name (name),
			KEY is_active (is_active)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'inventory_loans' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			item_id BIGINT UNSIGNED NOT NULL,
			user_id BIGINT UNSIGNED NOT NULL,
			borrowed_quantity INT UNSIGNED NOT NULL,
			borrowed_at DATETIME NOT NULL,
			due_date DATE NULL,
			returned_at DATETIME NULL,
			note TEXT NULL,
			return_note TEXT NULL,
			status VARCHAR(20) NOT NULL DEFAULT 'open',
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			KEY item_id (item_id),
			KEY user_id (user_id),
			KEY status (status),
			KEY borrowed_at (borrowed_at),
			KEY due_date (due_date)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'parcel_members' ) . " (
			parcel_id BIGINT UNSIGNED NOT NULL,
			user_id BIGINT UNSIGNED NOT NULL,
			created_at DATETIME NOT NULL,
			PRIMARY KEY  (parcel_id, user_id),
			KEY user_id (user_id)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'parcel_tenants' ) . " (
			parcel_id BIGINT UNSIGNED NOT NULL,
			tenant_id BIGINT UNSIGNED NOT NULL,
			created_at DATETIME NOT NULL,
			PRIMARY KEY  (parcel_id, tenant_id),
			KEY tenant_id (tenant_id)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'chat_messages' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			room_key VARCHAR(50) NOT NULL,
			user_id BIGINT UNSIGNED NOT NULL,
			message TEXT NOT NULL,
			created_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			KEY room_key (room_key),
			KEY user_id (user_id),
			KEY created_at (created_at)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'meter_readings' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			meter_id BIGINT UNSIGNED NOT NULL,
			parcel_id BIGINT UNSIGNED NOT NULL,
			reading_value DECIMAL(12,3) NOT NULL,
			reading_date DATE NOT NULL,
			note TEXT NULL,
			submitted_by BIGINT UNSIGNED NOT NULL DEFAULT 0,
			is_self_reading TINYINT(1) NOT NULL DEFAULT 0,
			created_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			KEY meter_id (meter_id),
			KEY parcel_id (parcel_id),
			KEY reading_date (reading_date)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'cost_years' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			entry_year SMALLINT UNSIGNED NOT NULL,
			power_price_per_kwh DECIMAL(12,4) NULL,
			water_price_per_m3 DECIMAL(12,4) NULL,
			statement_is_locked TINYINT(1) NOT NULL DEFAULT 0,
			statement_locked_at DATETIME NULL,
			statement_locked_by BIGINT UNSIGNED NOT NULL DEFAULT 0,
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			UNIQUE KEY entry_year (entry_year)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'cost_rates' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			entry_year SMALLINT UNSIGNED NOT NULL,
			section_id BIGINT UNSIGNED NOT NULL,
			power_price_per_kwh DECIMAL(12,4) NULL,
			water_price_per_m3 DECIMAL(12,4) NULL,
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			UNIQUE KEY year_section (entry_year, section_id),
			KEY section_id (section_id)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'cost_entries' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			entry_year SMALLINT UNSIGNED NOT NULL,
			name VARCHAR(190) NOT NULL,
			distribution_type VARCHAR(20) NOT NULL DEFAULT 'parcel',
			unit_amount DECIMAL(12,2) NULL,
			total_cost DECIMAL(12,2) NOT NULL DEFAULT 0.00,
			is_mandatory TINYINT(1) NOT NULL DEFAULT 1,
			note TEXT NULL,
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			KEY entry_year (entry_year),
			KEY name (name),
			KEY distribution_type (distribution_type)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'work_jobs' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			name VARCHAR(190) NOT NULL,
			description TEXT NULL,
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			UNIQUE KEY name (name)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'work_year_config' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			entry_year SMALLINT UNSIGNED NOT NULL,
			required_hours DECIMAL(8,2) NOT NULL DEFAULT 0.00,
			price_per_missing_hour DECIMAL(12,2) NOT NULL DEFAULT 0.00,
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			UNIQUE KEY entry_year (entry_year)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'work_logs' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			job_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
			work_date DATE NOT NULL,
			note TEXT NULL,
			created_at DATETIME NOT NULL,
			updated_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			KEY job_id (job_id),
			KEY work_date (work_date)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'work_log_members' ) . " (
			id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
			log_id BIGINT UNSIGNED NOT NULL,
			user_id BIGINT UNSIGNED NOT NULL,
			hours DECIMAL(8,2) NOT NULL DEFAULT 0.00,
			created_at DATETIME NOT NULL,
			PRIMARY KEY  (id),
			UNIQUE KEY log_user (log_id, user_id),
			KEY user_id (user_id),
			KEY log_id (log_id)
		) {$charset_collate};";

		$sql[] = "CREATE TABLE " . self::table( 'parcel_cost_assignments' ) . " (
			parcel_id BIGINT UNSIGNED NOT NULL,
			cost_entry_id BIGINT UNSIGNED NOT NULL,
			created_at DATETIME NOT NULL,
			PRIMARY KEY  (parcel_id, cost_entry_id),
			KEY cost_entry_id (cost_entry_id)
		) {$charset_collate};";

		foreach ( $sql as $statement ) {
			dbDelta( $statement );
		}
	}

	/**
	 * Optimize plugin tables.
	 *
	 * @return void
	 */
	public static function optimize_tables() {
		global $wpdb;

		$tables = array(
			self::table( 'sections' ),
			self::table( 'parcels' ),
			self::table( 'meters' ),
			self::table( 'tenants' ),
			self::table( 'inventory_items' ),
			self::table( 'inventory_loans' ),
			self::table( 'parcel_members' ),
			self::table( 'parcel_tenants' ),
			self::table( 'chat_messages' ),
			self::table( 'meter_readings' ),
			self::table( 'cost_years' ),
			self::table( 'cost_rates' ),
			self::table( 'cost_entries' ),
			self::table( 'work_jobs' ),
			self::table( 'work_year_config' ),
			self::table( 'work_logs' ),
			self::table( 'work_log_members' ),
			self::table( 'parcel_cost_assignments' ),
		);

		foreach ( $tables as $table ) {
			if ( ! empty( $table ) ) {
				$wpdb->query( 'OPTIMIZE TABLE `' . esc_sql( $table ) . '`' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
			}
		}
	}

	/**
	 * Drop plugin tables during uninstall.
	 *
	 * @return void
	 */
	public static function drop_tables() {
		global $wpdb;

		$tables = array(
			self::table( 'parcel_cost_assignments' ),
			self::table( 'work_log_members' ),
			self::table( 'work_logs' ),
			self::table( 'work_year_config' ),
			self::table( 'work_jobs' ),
			self::table( 'inventory_loans' ),
			self::table( 'inventory_items' ),
			self::table( 'cost_entries' ),
			self::table( 'cost_rates' ),
			self::table( 'cost_years' ),
			self::table( 'chat_messages' ),
			self::table( 'meter_readings' ),
			self::table( 'parcel_members' ),
			self::table( 'parcel_tenants' ),
			self::table( 'meters' ),
			self::table( 'parcels' ),
			self::table( 'tenants' ),
			self::table( 'sections' ),
		);

		foreach ( $tables as $table ) {
			if ( $table ) {
				$wpdb->query( "DROP TABLE IF EXISTS {$table}" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
			}
		}
	}
}
