<?php
/**
 * GGM Commerce Order Notes Class
 *
 * Handles structured order notes with visibility control.
 * Note types:
 * - private: Only visible to admin (default)
 * - picking: Visible on packing/picking lists
 * - customer: Visible to customer (invoice, order confirmation, account)
 *
 * @package GGM_Commerce
 */

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter

/**
 * Class GGM_Commerce_Order_Notes
 */
class GGM_Commerce_Order_Notes {

	/**
	 * Note type constants.
	 */
	const TYPE_PRIVATE  = 'private';
	const TYPE_PICKING  = 'picking';
	const TYPE_CUSTOMER = 'customer';

	/**
	 * Add a note to an order.
	 *
	 * @param int    $order_id  The order ID.
	 * @param string $content   The note content.
	 * @param string $note_type The note type (private, picking, customer).
	 * @param bool   $is_system Whether this is a system-generated note.
	 * @return int|false The note ID on success, false on failure.
	 */
	public static function add_note( $order_id, $content, $note_type = self::TYPE_PRIVATE, $is_system = false ) {
		global $wpdb;

		// Validate note type.
		$valid_types = array( self::TYPE_PRIVATE, self::TYPE_PICKING, self::TYPE_CUSTOMER );
		if ( ! in_array( $note_type, $valid_types, true ) ) {
			$note_type = self::TYPE_PRIVATE;
		}

		// Get current user info.
		$user_id   = get_current_user_id();
		$user_name = '';
		if ( $user_id ) {
			$user = get_userdata( $user_id );
			$user_name = $user->display_name ? $user->display_name : $user->user_login;
		} elseif ( $is_system ) {
			$user_name = 'System';
		}

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
		$result = $wpdb->insert(
			"{$wpdb->prefix}ggmc_order_notes",
			array(
				'order_id'        => $order_id,
				'note_type'       => $note_type,
				'content'         => $content,
				'is_system'       => $is_system ? 1 : 0,
				'created_by'      => $user_id ? $user_id : null,
				'created_by_name' => $user_name,
				'created_at'      => current_time( 'mysql' ),
			),
			array( '%d', '%s', '%s', '%d', '%d', '%s', '%s' )
		);

		if ( $result ) {
			return $wpdb->insert_id;
		}

		return false;
	}

	/**
	 * Add a system note (status change, payment, etc).
	 *
	 * @param int    $order_id The order ID.
	 * @param string $content  The note content.
	 * @return int|false The note ID on success, false on failure.
	 */
	public static function add_system_note( $order_id, $content ) {
		return self::add_note( $order_id, $content, self::TYPE_PRIVATE, true );
	}

	/**
	 * Get notes for an order.
	 *
	 * @param int          $order_id   The order ID.
	 * @param string|array $note_types Optional. Filter by note type(s).
	 * @param bool         $include_system Optional. Include system notes. Default true.
	 * @return array Array of note objects.
	 */
	public static function get_notes( $order_id, $note_types = null, $include_system = true ) {
		global $wpdb;

		$where_clauses = array( 'order_id = %d' );
		$where_values  = array( $order_id );

		// Filter by note type.
		if ( $note_types !== null ) {
			if ( is_string( $note_types ) ) {
				$note_types = array( $note_types );
			}
			$placeholders    = implode( ',', array_fill( 0, count( $note_types ), '%s' ) );
			$where_clauses[] = "note_type IN ($placeholders)";
			$where_values    = array_merge( $where_values, $note_types );
		}

		// Exclude system notes if requested.
		if ( ! $include_system ) {
			$where_clauses[] = 'is_system = 0';
		}

		$where_sql = implode( ' AND ', $where_clauses );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$notes = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}ggmc_order_notes WHERE $where_sql ORDER BY created_at DESC",
				$where_values
			)
		);

		return $notes ? $notes : array();
	}

	/**
	 * Get all notes for an order (admin view).
	 *
	 * @param int $order_id The order ID.
	 * @return array Array of note objects.
	 */
	public static function get_all_notes( $order_id ) {
		return self::get_notes( $order_id, null, true );
	}

	/**
	 * Get customer-visible notes for an order.
	 *
	 * @param int $order_id The order ID.
	 * @return array Array of note objects.
	 */
	public static function get_customer_notes( $order_id ) {
		return self::get_notes( $order_id, self::TYPE_CUSTOMER, false );
	}

	/**
	 * Get picking/packing list notes for an order.
	 *
	 * @param int $order_id The order ID.
	 * @return array Array of note objects.
	 */
	public static function get_picking_notes( $order_id ) {
		return self::get_notes( $order_id, self::TYPE_PICKING, false );
	}

	/**
	 * Delete a note.
	 *
	 * @param int $note_id The note ID.
	 * @return bool True on success, false on failure.
	 */
	public static function delete_note( $note_id ) {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$result = $wpdb->delete(
			"{$wpdb->prefix}ggmc_order_notes",
			array( 'id' => $note_id ),
			array( '%d' )
		);

		return $result !== false;
	}

	/**
	 * Migrate legacy notes from orders table to notes table.
	 * This should be run once during upgrade.
	 *
	 * @return int Number of orders migrated.
	 */
	public static function migrate_legacy_notes() {
		global $wpdb;

		// Get all orders with notes in the legacy format.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$orders = $wpdb->get_results(
			"SELECT id, notes FROM {$wpdb->prefix}ggmc_orders WHERE notes IS NOT NULL AND notes != ''"
		);

		if ( empty( $orders ) ) {
			return 0;
		}

		$migrated = 0;

		foreach ( $orders as $order ) {
			// Check if this order already has notes in the new table.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$existing = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_order_notes WHERE order_id = %d",
					$order->id
				)
			);

			if ( $existing > 0 ) {
				continue; // Already migrated.
			}

			// Parse the legacy notes format: [timestamp] message (by user)
			$notes_text = $order->notes;
			$lines      = explode( "\n", $notes_text );

			foreach ( $lines as $line ) {
				$line = trim( $line );
				if ( empty( $line ) ) {
					continue;
				}

				// Try to parse the structured format.
				$is_system    = false;
				$created_at   = current_time( 'mysql' );
				$created_name = '';
				$content      = $line;

				// Match format: [2024-01-08 14:30:00] Content (by Admin Name)
				if ( preg_match( '/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]\s*(.+?)(?:\s*\(by ([^)]+)\))?$/', $line, $matches ) ) {
					$created_at = $matches[1];
					$content    = $matches[2];
					if ( ! empty( $matches[3] ) ) {
						$created_name = $matches[3];
					}

					// Check if this looks like a system note (status change).
					if ( strpos( $content, 'Order Status:' ) !== false || strpos( $content, 'Payment Status:' ) !== false ) {
						$is_system = true;
					}
				}

				// Insert as private note (legacy notes were all visible, but default to private for safety).
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
				$wpdb->insert(
					"{$wpdb->prefix}ggmc_order_notes",
					array(
						'order_id'        => $order->id,
						'note_type'       => self::TYPE_PRIVATE,
						'content'         => $content,
						'is_system'       => $is_system ? 1 : 0,
						'created_by'      => null,
						'created_by_name' => $created_name,
						'created_at'      => $created_at,
					),
					array( '%d', '%s', '%s', '%d', '%d', '%s', '%s' )
				);
			}

			$migrated++;
		}

		return $migrated;
	}

	/**
	 * Get note type label for display.
	 *
	 * @param string $note_type The note type.
	 * @return string The display label.
	 */
	public static function get_type_label( $note_type ) {
		$labels = array(
			self::TYPE_PRIVATE  => 'Private',
			self::TYPE_PICKING  => 'Picking List',
			self::TYPE_CUSTOMER => 'Customer',
		);

		return isset( $labels[ $note_type ] ) ? $labels[ $note_type ] : 'Private';
	}

	/**
	 * Get note type badge HTML for admin display.
	 *
	 * @param string $note_type The note type.
	 * @return string HTML badge.
	 */
	public static function get_type_badge( $note_type ) {
		$colors = array(
			self::TYPE_PRIVATE  => array( 'bg' => '#f0f0f1', 'color' => '#50575e' ),
			self::TYPE_PICKING  => array( 'bg' => '#fff8e5', 'color' => '#996800' ),
			self::TYPE_CUSTOMER => array( 'bg' => '#d4edda', 'color' => '#155724' ),
		);

		$style = isset( $colors[ $note_type ] ) ? $colors[ $note_type ] : $colors[ self::TYPE_PRIVATE ];
		$label = self::get_type_label( $note_type );

		return sprintf(
			'<span style="display: inline-block; padding: 2px 8px; border-radius: 3px; font-size: 11px; background: %s; color: %s;">%s</span>',
			esc_attr( $style['bg'] ),
			esc_attr( $style['color'] ),
			esc_html( $label )
		);
	}
}

/**
 * Helper function to get the order notes instance.
 *
 * @return GGM_Commerce_Order_Notes
 */
function ggm_commerce_order_notes() {
	return new GGM_Commerce_Order_Notes();
}
