<?php
/**
 * Parent front-end portal: session, login, logout, password reset.
 *
 * Mirrors TSM_Public (students) and TSM_Teacher_Portal (teachers). Parents
 * are **not** WordPress users  -  they live in the dedicated `tsm_parents`
 * table with their own password_hash, reset_token, and cookie session.
 *
 * @package TradeSchoolManager
 * @since 1.19.5
 */

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

class TSM_Parent_Portal {

	const COOKIE = 'tsm_parent_session';
	private static $instance = null;

	public static function instance() {
		if ( null === self::$instance ) { self::$instance = new self(); }
		return self::$instance;
	}

	private function __construct() {
		add_action( 'init', array( $this, 'maybe_handle_logout' ) );
		add_action( 'init', array( $this, 'maybe_handle_login' ) );
		add_action( 'init', array( $this, 'maybe_handle_forgot' ) );
		add_action( 'init', array( $this, 'maybe_handle_reset' ) );
		add_action( 'init', array( $this, 'maybe_handle_change_password' ) );
		add_action( 'init', array( $this, 'maybe_handle_profile' ) );
	}

	/* ------------------------------------------------------------------ */
	/* Session                                                            */
	/* ------------------------------------------------------------------ */

	public static function set_current( $parent_id ) {
		$token = wp_generate_password( 32, false, false );
		set_transient( 'tsm_parent_session_' . $token, (int) $parent_id, DAY_IN_SECONDS * 7 );
		setcookie( self::COOKIE, $token, time() + DAY_IN_SECONDS * 7, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true );
		$_COOKIE[ self::COOKIE ] = $token;
	}

	public static function current_parent_id() {
		if ( empty( $_COOKIE[ self::COOKIE ] ) ) { return 0; }
		$token = sanitize_text_field( wp_unslash( $_COOKIE[ self::COOKIE ] ) );
		$id    = get_transient( 'tsm_parent_session_' . $token );
		return $id ? (int) $id : 0;
	}

	public static function logout() {
		if ( ! empty( $_COOKIE[ self::COOKIE ] ) ) {
			delete_transient( 'tsm_parent_session_' . sanitize_text_field( wp_unslash( $_COOKIE[ self::COOKIE ] ) ) );
		}
		setcookie( self::COOKIE, '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN );
		unset( $_COOKIE[ self::COOKIE ] );
	}

	/**
	 * Verify a parent login. Returns the row on success, or a string
	 * reason code on failure ('no_user', 'no_password', 'bad_password').
	 */
	public static function verify_login( $login, $password ) {
		global $wpdb;
		$t = TSM_Parents::parents_table();
		$login = trim( (string) $login );
		if ( '' === $login ) { return 'no_user'; }
		// Match on email (case-insensitive) or username.
		$row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$t} WHERE LOWER(email) = LOWER(%s) OR username = %s LIMIT 1", $login, $login ) ); // phpcs:ignore
		if ( ! $row ) { return 'no_user'; }
		if ( empty( $row->password_hash ) ) { return 'no_password'; }
		if ( wp_check_password( $password, $row->password_hash ) ) { return $row; }
		return 'bad_password';
	}

	/* ------------------------------------------------------------------ */
	/* Handlers                                                           */
	/* ------------------------------------------------------------------ */

	public function maybe_handle_logout() {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Logout link is a simple GET flag; clears local cookie only.
		if ( ! isset( $_GET['tsm_parent_logout'] ) ) { return; }
		self::logout();
		wp_safe_redirect( add_query_arg( 'tsm_p_logged_out', 1, TSM_Parents::portal_url() ) );
		exit;
	}

	public function maybe_handle_login() {
		if ( ! isset( $_POST['tsm_parent_login'] ) ) { return; }
		if ( ! isset( $_POST['tsm_parent_login_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['tsm_parent_login_nonce'] ) ), 'tsm_parent_login' ) ) {
			return;
		}
		$login = sanitize_text_field( wp_unslash( $_POST['tsm_parent_username'] ?? '' ) );
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Raw password verified against hash; sanitizing would corrupt.
		$pass  = (string) wp_unslash( $_POST['tsm_parent_password'] ?? '' );
		$result = self::verify_login( $login, $pass );
		if ( is_object( $result ) ) {
			self::set_current( (int) $result->id );
			wp_safe_redirect( remove_query_arg( array( 'tsm_p_login_error', 'tsm_p_login_reason', 'tsm_p_logged_out' ), TSM_Parents::portal_url() ) );
			exit;
		}
		if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
			// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
			error_log( '[TSM Parent Login] failed for "' . $login . '" reason=' . (string) $result );
		}
		wp_safe_redirect( add_query_arg( array( 'tsm_p_login_error' => 1, 'tsm_p_login_reason' => (string) $result ), TSM_Parents::portal_url() ) );
		exit;
	}

	public function maybe_handle_forgot() {
		if ( empty( $_POST['tsm_parent_forgot_nonce'] ) ) { return; }
		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['tsm_parent_forgot_nonce'] ) ), 'tsm_parent_forgot' ) ) { return; }
		$email = sanitize_email( wp_unslash( $_POST['tsm_parent_email'] ?? '' ) );
		$row   = $email ? TSM_Parents::get_by_email( $email ) : null;
		if ( $row ) {
			TSM_Parents::send_reset_email( $row );
		}
		// Always show generic success (no email enumeration).
		wp_safe_redirect( add_query_arg( 'tsm_p_forgot_sent', 1, TSM_Parents::portal_url() ) );
		exit;
	}

	public function maybe_handle_reset() {
		if ( empty( $_POST['tsm_parent_reset_nonce'] ) ) { return; }
		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['tsm_parent_reset_nonce'] ) ), 'tsm_parent_reset' ) ) { return; }
		$token = sanitize_text_field( wp_unslash( $_POST['tsm_parent_reset_token'] ?? '' ) );
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Raw password; sanitizing would corrupt.
		$p1    = (string) wp_unslash( $_POST['tsm_parent_new_password']  ?? '' );
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Raw password; sanitizing would corrupt.
		$p2    = (string) wp_unslash( $_POST['tsm_parent_new_password2'] ?? '' );
		$row   = TSM_Parents::get_by_reset_token( $token );
		if ( ! $row ) {
			wp_safe_redirect( add_query_arg( 'tsm_p_reset_error', 'invalid', TSM_Parents::portal_url() ) ); exit;
		}
		if ( strlen( $p1 ) < 8 ) {
			wp_safe_redirect( add_query_arg( array( 'tsm_p_reset' => $token, 'tsm_p_reset_error' => 'short' ), TSM_Parents::portal_url() ) ); exit;
		}
		if ( $p1 !== $p2 ) {
			wp_safe_redirect( add_query_arg( array( 'tsm_p_reset' => $token, 'tsm_p_reset_error' => 'mismatch' ), TSM_Parents::portal_url() ) ); exit;
		}
		TSM_Parents::set_password( (int) $row->id, $p1 );
		self::set_current( (int) $row->id );
		wp_safe_redirect( add_query_arg( 'tsm_p_reset_done', 1, TSM_Parents::portal_url() ) );
		exit;
	}

	public function maybe_handle_change_password() {
		if ( empty( $_POST['tsm_parent_chpw_nonce'] ) ) { return; }
		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['tsm_parent_chpw_nonce'] ) ), 'tsm_parent_chpw' ) ) { return; }
		$pid = self::current_parent_id();
		if ( ! $pid ) { return; }
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Raw password; sanitizing would corrupt.
		$cur = (string) wp_unslash( $_POST['tsm_parent_current_password'] ?? '' );
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Raw password; sanitizing would corrupt.
		$p1  = (string) wp_unslash( $_POST['tsm_parent_new_password']     ?? '' );
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Raw password; sanitizing would corrupt.
		$p2  = (string) wp_unslash( $_POST['tsm_parent_new_password2']    ?? '' );
		$row = TSM_Parents::get( $pid );
		$return = add_query_arg( 'tab', 'settings', TSM_Parents::portal_url() );
		if ( ! $row || ! wp_check_password( $cur, $row->password_hash ) ) {
			wp_safe_redirect( add_query_arg( 'tsm_pw_msg', 'current', $return ) ); exit;
		}
		if ( strlen( $p1 ) < 8 ) { wp_safe_redirect( add_query_arg( 'tsm_pw_msg', 'short', $return ) ); exit; }
		if ( $p1 !== $p2 )        { wp_safe_redirect( add_query_arg( 'tsm_pw_msg', 'mismatch', $return ) ); exit; }
		TSM_Parents::set_password( $pid, $p1 );
		wp_safe_redirect( add_query_arg( 'tsm_pw_msg', 'ok', $return ) );
		exit;
	}

	public function maybe_handle_profile() {
		if ( empty( $_POST['tsm_parent_profile_nonce'] ) ) { return; }
		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['tsm_parent_profile_nonce'] ) ), 'tsm_parent_profile' ) ) { return; }
		$pid = self::current_parent_id();
		if ( ! $pid ) { return; }
		$return = add_query_arg( 'tab', 'settings', TSM_Parents::portal_url() );
		$email = sanitize_email( wp_unslash( $_POST['email'] ?? '' ) );
		$first = sanitize_text_field( wp_unslash( $_POST['first_name'] ?? '' ) );
		$last  = sanitize_text_field( wp_unslash( $_POST['last_name']  ?? '' ) );
		$phone = sanitize_text_field( wp_unslash( $_POST['phone']      ?? '' ) );
		if ( ! is_email( $email ) ) {
			wp_safe_redirect( add_query_arg( 'tsm_profile_saved', 'bad_email', $return ) ); exit;
		}
		$other = TSM_Parents::get_by_email( $email );
		if ( $other && (int) $other->id !== (int) $pid ) {
			wp_safe_redirect( add_query_arg( 'tsm_profile_saved', 'email_taken', $return ) ); exit;
		}
		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Plugin-owned parents table; no relevant object cache.
		$wpdb->update( TSM_Parents::parents_table(), array(
			'email'      => $email,
			'first_name' => $first,
			'last_name'  => $last,
			'phone'      => $phone,
		), array( 'id' => $pid ) );
		wp_safe_redirect( add_query_arg( 'tsm_profile_saved', 'ok', $return ) );
		exit;
	}
}
