<?php
/**
 * School Year / Term CRUD.
 *
 * @package TradeSchoolManager
 */

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

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Plugin-owned custom tables; table names interpolated only; user values always pass through $wpdb->prepare().

class TSM_School_Years {

	public static function table() {
		global $wpdb;
		return $wpdb->prefix . 'tsm_school_years';
	}

	public static function all() {
		global $wpdb;
		$t = self::table();
		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		return $wpdb->get_results( "SELECT * FROM {$t} ORDER BY start_date DESC, id DESC" );
	}

	public static function get( $id ) {
		global $wpdb;
		$t = self::table();
		return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$t} WHERE id = %d", absint( $id ) ) );
	}

	public static function save( $data, $id = 0 ) {
		global $wpdb;
		$t      = self::table();
		$record = array(
			'name'       => sanitize_text_field( $data['name'] ?? '' ),
			'start_date' => ! empty( $data['start_date'] ) ? sanitize_text_field( $data['start_date'] ) : null,
			'end_date'   => ! empty( $data['end_date'] ) ? sanitize_text_field( $data['end_date'] ) : null,
			'status'     => sanitize_text_field( $data['status'] ?? 'active' ),
		);
		if ( $id ) {
			$wpdb->update( $t, $record, array( 'id' => absint( $id ) ) );
			return absint( $id );
		}
		$wpdb->insert( $t, $record );
		return (int) $wpdb->insert_id;
	}

	public static function delete( $id ) {
		global $wpdb;
		$wpdb->delete( self::table(), array( 'id' => absint( $id ) ) );
	}

	/**
	 * The "current" school year  -  most recent unarchived active year.
	 * Returns the row object (or null when no years exist).
	 */
	public static function current() {
		global $wpdb;
		$t   = self::table();
		$row = $wpdb->get_row( "SELECT * FROM {$t} WHERE archived = 0 AND status = 'active' ORDER BY start_date DESC, id DESC LIMIT 1" ); // phpcs:ignore
		if ( $row ) { return $row; }
		return $wpdb->get_row( "SELECT * FROM {$t} ORDER BY start_date DESC, id DESC LIMIT 1" ); // phpcs:ignore
	}

	/**
	 * Is the given year archived? Year 0 (= "all years") is never archived.
	 * Centralized so admin save handlers, classes, assignments, grades,
	 * attendance, and enrollments can all enforce a single lockdown rule.
	 */
	public static function is_archived( $year_id ) {
		$year_id = absint( $year_id );
		if ( ! $year_id ) { return false; }
		$row = self::get( $year_id );
		return $row && ! empty( $row->archived );
	}

	/**
	 * Is the currently-selected active year (admin top-bar switcher) archived?
	 * Returns false for "All years" (id=0) so cross-year work isn't blocked.
	 */
	public static function is_active_year_archived() {
		if ( ! class_exists( 'TSM_Active_Year' ) ) { return false; }
		$active = (int) TSM_Active_Year::get();
		return self::is_archived( $active );
	}

	/**
	 * Roll classes (and their assignments) from one year into another.
	 *
	 * Per user spec: copies class definitions + assignments only. Roster,
	 * grades, attendance, and certificates are NOT copied  -  every cloned
	 * class starts with an empty gradebook and empty attendance log so
	 * the new year is a clean slate. Original year's data is untouched
	 * and remains fully readable for historical reports/invoices/PDFs.
	 *
	 * @param int   $from_year_id  Source year ID.
	 * @param int   $to_year_id    Destination year ID (must already exist).
	 * @param array $class_ids     Optional whitelist of class IDs to copy
	 *                             (empty = all classes in the source year).
	 * @return array { copied_classes: int, copied_assignments: int, mapping: [old_class_id => new_class_id] }
	 */
	public static function rollover( $from_year_id, $to_year_id, $class_ids = array() ) {
		$from_year_id = absint( $from_year_id );
		$to_year_id   = absint( $to_year_id );
		$result       = array( 'copied_classes' => 0, 'copied_assignments' => 0, 'mapping' => array() );

		if ( ! $from_year_id || ! $to_year_id || $from_year_id === $to_year_id ) {
			return $result;
		}
		if ( ! self::get( $to_year_id ) || ! self::get( $from_year_id ) ) {
			return $result;
		}

		$source_classes = TSM_Classes::all( $from_year_id );
		$whitelist      = array_map( 'absint', (array) $class_ids );

		foreach ( $source_classes as $src ) {
			if ( ! empty( $whitelist ) && ! in_array( (int) $src->id, $whitelist, true ) ) {
				continue;
			}
			// Clone the class definition into the target year.
			$new_class_id = TSM_Classes::save( array(
				'school_year_id' => $to_year_id,
				'name'           => $src->name,
				'description'    => $src->description,
				'grading_method' => $src->grading_method,
				'grading_config' => json_decode( $src->grading_config, true ) ?: array(),
				'teacher_id'     => $src->teacher_id,
				'status'         => 'active',
			) );
			if ( ! $new_class_id ) { continue; }

			$result['mapping'][ (int) $src->id ] = (int) $new_class_id;
			$result['copied_classes']++;

			// Clone every assignment, but reset due/assigned dates so the
			// new year's instructor can re-schedule them. Points possible,
			// category, EC flags, required flag, and description carry over.
			$assignments = TSM_Assignments::for_class( $src->id );
			foreach ( $assignments as $a ) {
				$new_aid = TSM_Assignments::save( array(
					'class_id'        => $new_class_id,
					'school_year_id'  => $to_year_id,
					'title'           => $a->title,
					'description'     => $a->description,
					'category'        => $a->category,
					'assigned_date'   => null,
					'due_date'        => null,
					'points_possible' => $a->points_possible,
					'extra_credit'    => (int) $a->extra_credit,
					'required'        => (int) $a->required,
				) );
				if ( $new_aid ) { $result['copied_assignments']++; }
			}
		}

		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- "tsm_" is this plugin's registered prefix (see phpcs.xml.dist).
		do_action( 'tradeschool_manager_after_year_rollover', $from_year_id, $to_year_id, $result );
		return $result;
	}
}
