<?php
declare(strict_types=1);
namespace ConfManager\Events;

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


use ConfManager\Traits\Singleton;
use ConfManager\Traits\HasHooks;

/**
 * イベントREST APIエンドポイント
 *
 * @since 1.0.0
 */
class EventApi {

	use Singleton;
	use HasHooks;

	private const NAMESPACE = 'conf-manager/v1';
	private const REST_BASE = 'events';

	protected function init(): void {
		$this->register_hooks();
	}

	protected function register_hooks(): void {
		$this->add_action( 'rest_api_init', [ $this, 'register_routes' ] );
	}

	public function register_routes(): void {
		register_rest_route( self::NAMESPACE, '/' . self::REST_BASE, [
			[
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => [ $this, 'get_items' ],
				'permission_callback' => fn() => current_user_can( 'conf_manager_view_events' ),
			],
			[
				'methods'             => \WP_REST_Server::CREATABLE,
				'callback'            => [ $this, 'create_item' ],
				'permission_callback' => fn() => current_user_can( 'conf_manager_edit_events' ),
			],
		] );

		register_rest_route( self::NAMESPACE, '/' . self::REST_BASE . '/(?P<id>[\d]+)', [
			[
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => [ $this, 'get_item' ],
				'permission_callback' => fn() => current_user_can( 'conf_manager_view_events' ),
			],
			[
				'methods'             => \WP_REST_Server::EDITABLE,
				'callback'            => [ $this, 'update_item' ],
				'permission_callback' => fn() => current_user_can( 'conf_manager_edit_events' ),
			],
			[
				'methods'             => \WP_REST_Server::DELETABLE,
				'callback'            => [ $this, 'delete_item' ],
				'permission_callback' => fn() => current_user_can( 'conf_manager_edit_events' ),
			],
		] );

		// 催しをキャンセルしたら何件が巻き込まれるかを、押す前に見せるための口。
		// 🔴 実際に動かす delete() と**同じリゾルバ**を読む（件数がずれないように）。
		register_rest_route( self::NAMESPACE, '/' . self::REST_BASE . '/(?P<id>[\d]+)/cancel-impact', [
			[
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => [ $this, 'get_cancel_impact' ],
				'permission_callback' => fn() => current_user_can( 'conf_manager_edit_events' ),
			],
		] );

		register_rest_route( self::NAMESPACE, '/' . self::REST_BASE . '/(?P<id>[\d]+)/sessions', [
			[
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => [ $this, 'get_sessions' ],
				'permission_callback' => fn() => current_user_can( 'conf_manager_view_events' ),
			],
		] );

		// 演題投稿用Wordテンプレート管理
		register_rest_route( self::NAMESPACE, '/' . self::REST_BASE . '/(?P<id>[\d]+)/template', [
			[
				'methods'             => \WP_REST_Server::CREATABLE,
				'callback'            => [ $this, 'upload_template' ],
				'permission_callback' => fn() => current_user_can( 'conf_manager_edit_events' ),
			],
			[
				'methods'             => \WP_REST_Server::DELETABLE,
				'callback'            => [ $this, 'delete_template' ],
				'permission_callback' => fn() => current_user_can( 'conf_manager_edit_events' ),
			],
		] );

	}

	public function get_items( \WP_REST_Request $request ): \WP_REST_Response {
		$result = EventManager::instance()->search( [
			'keyword'  => $request->get_param( 'keyword' ),
			'status'   => $request->get_param( 'status' ),
			'from'     => $request->get_param( 'from' ),
			'to'       => $request->get_param( 'to' ),
			'orderby'  => $request->get_param( 'orderby' ) ?? 'date_start',
			'order'    => $request->get_param( 'order' ) ?? 'DESC',
			'per_page' => $request->get_param( 'per_page' ) ?? 20,
			'page'     => $request->get_param( 'page' ) ?? 1,
		] );

		$response = new \WP_REST_Response( $result['items'], 200 );
		$response->header( 'X-WP-Total', (string) $result['total'] );
		$response->header( 'X-WP-TotalPages', (string) max( 1, (int) ceil( $result['total'] / $result['per_page'] ) ) );

		return $response;
	}

	public function get_item( \WP_REST_Request $request ): \WP_REST_Response|\WP_Error {
		$event = EventManager::instance()->get( (int) $request['id'] );
		if ( null === $event ) {
			return new \WP_Error( 'not_found', __( 'Event not found.', 'conferencemanager' ), [ 'status' => 404 ] );
		}
		return new \WP_REST_Response( $event, 200 );
	}

	public function create_item( \WP_REST_Request $request ): \WP_REST_Response|\WP_Error {
		$data = [
			'title'                => $request->get_param( 'title' ),
			'description'          => $request->get_param( 'description' ),
			'date_start'           => $request->get_param( 'date_start' ),
			'date_end'             => $request->get_param( 'date_end' ),
			'venue'                => $request->get_param( 'venue' ),
			'venue_address'        => $request->get_param( 'venue_address' ),
			'capacity'             => $request->get_param( 'capacity' ),
			'reg_start'            => $request->get_param( 'reg_start' ),
			'reg_end'              => $request->get_param( 'reg_end' ),
			'fee_rules'              => $request->get_param( 'fee_rules' ),
			'advance_fee_deadline'   => $request->get_param( 'advance_fee_deadline' ),
			'fee_rules_day'          => $request->get_param( 'fee_rules_day' ),
			'advance_fee_notice'     => $request->get_param( 'advance_fee_notice' ),
			'payment_account_name'   => $request->get_param( 'payment_account_name' ),
			'payment_account_info'   => $request->get_param( 'payment_account_info' ),
			'organizer_info'         => $request->get_param( 'organizer_info' ),
			'submission_start'       => $request->get_param( 'submission_start' ),
			'submission_end'         => $request->get_param( 'submission_end' ),
			'submission_settings'    => $request->get_param( 'submission_settings' ),
			'tax_rate'               => $request->get_param( 'tax_rate' ),
		];

		$result = EventManager::instance()->create( $data );
		if ( is_wp_error( $result ) ) {
			$result->add_data( [ 'status' => 400 ] );
			return $result;
		}

		return new \WP_REST_Response( EventManager::instance()->get( $result ), 201 );
	}

	public function update_item( \WP_REST_Request $request ): \WP_REST_Response|\WP_Error {
		$id   = (int) $request['id'];
		$data = array_filter( [
			'title'                => $request->get_param( 'title' ),
			'description'          => $request->get_param( 'description' ),
			'date_start'           => $request->get_param( 'date_start' ),
			'date_end'             => $request->get_param( 'date_end' ),
			'venue'                => $request->get_param( 'venue' ),
			'venue_address'        => $request->get_param( 'venue_address' ),
			'capacity'             => $request->get_param( 'capacity' ),
			'reg_start'            => $request->get_param( 'reg_start' ),
			'reg_end'              => $request->get_param( 'reg_end' ),
			'fee_rules'              => $request->get_param( 'fee_rules' ),
			'advance_fee_deadline'   => $request->get_param( 'advance_fee_deadline' ),
			'fee_rules_day'          => $request->get_param( 'fee_rules_day' ),
			'advance_fee_notice'     => $request->get_param( 'advance_fee_notice' ),
			'status'                 => $request->get_param( 'status' ),
			'payment_account_name'   => $request->get_param( 'payment_account_name' ),
			'payment_account_info'   => $request->get_param( 'payment_account_info' ),
			'organizer_info'         => $request->get_param( 'organizer_info' ),
			'submission_start'       => $request->get_param( 'submission_start' ),
			'submission_end'         => $request->get_param( 'submission_end' ),
			'submission_settings'    => $request->get_param( 'submission_settings' ),
			'tax_rate'               => $request->get_param( 'tax_rate' ),
		], fn( $v ) => null !== $v );

		$result = EventManager::instance()->update( $id, $data );
		if ( is_wp_error( $result ) ) {
			$status = 'not_found' === $result->get_error_code() ? 404 : 400;
			$result->add_data( [ 'status' => $status ] );
			return $result;
		}

		return new \WP_REST_Response( EventManager::instance()->get( $id ), 200 );
	}

	public function delete_item( \WP_REST_Request $request ): \WP_REST_Response|\WP_Error {
		// 🔴 既定は false。指定が無いときは申込を巻き込まない
		//    （古い呼び出し元や、うっかり省いた場合に連鎖させないため）。
		$cancel_registrations = filter_var( $request['cancel_registrations'] ?? false, FILTER_VALIDATE_BOOLEAN );

		$result = EventManager::instance()->delete( (int) $request['id'], $cancel_registrations );
		if ( is_wp_error( $result ) ) {
			$result->add_data( [ 'status' => 404 ] );
			return $result;
		}
		return new \WP_REST_Response( [ 'deleted' => true ], 200 );
	}

	/**
	 * GET /events/{id}/cancel-impact — キャンセルで巻き込まれる件数
	 */
	public function get_cancel_impact( \WP_REST_Request $request ): \WP_REST_Response {
		$impact = EventManager::instance()->get_cancel_impact( (int) $request['id'] );

		// ID の配列は画面では使わない（件数だけ見せる）。無用に外へ出さない。
		unset( $impact['cancellable_ids'] );

		return new \WP_REST_Response( $impact, 200 );
	}

	public function get_sessions( \WP_REST_Request $request ): \WP_REST_Response {
		$sessions = SessionManager::instance()->get_by_event( (int) $request['id'] );
		return new \WP_REST_Response( $sessions, 200 );
	}

	/**
	 * 演題投稿用Wordテンプレートをアップロードする
	 */
	public function upload_template( \WP_REST_Request $request ): \WP_REST_Response|\WP_Error {
		$event_id = (int) $request['id'];
		$event    = EventManager::instance()->get( $event_id );
		if ( null === $event ) {
			return new \WP_Error( 'not_found', __( 'Event not found.', 'conferencemanager' ), [ 'status' => 404 ] );
		}

		$files = $request->get_file_params();
		if ( empty( $files['file'] ) ) {
			return new \WP_Error( 'no_file', __( 'No file selected.', 'conferencemanager' ), [ 'status' => 400 ] );
		}

		$file = $files['file'];

		// 拡張子チェック
		$ext = strtolower( pathinfo( $file['name'], PATHINFO_EXTENSION ) );
		if ( 'docx' !== $ext ) {
			return new \WP_Error( 'invalid_extension', __( 'Only .docx files can be uploaded.', 'conferencemanager' ), [ 'status' => 400 ] );
		}

		// 20MB上限
		if ( $file['size'] > 20 * 1024 * 1024 ) {
			return new \WP_Error( 'file_too_large', __( 'The file size exceeds 20 MB.', 'conferencemanager' ), [ 'status' => 400 ] );
		}

		// WordPressメディアライブラリにアップロード
		$upload_filter = function ( $dirs ) use ( $event_id ) {
			$subdir         = '/conf-manager/templates/' . $event_id;
			$dirs['subdir'] = $subdir;
			$dirs['path']   = $dirs['basedir'] . $subdir;
			$dirs['url']    = $dirs['baseurl'] . $subdir;
			return $dirs;
		};
		add_filter( 'upload_dir', $upload_filter );

		// REST API コンテキストでは wp-admin/includes/file.php が自動 include されないため、
		// wp_handle_upload() を使う直前に明示的に読み込む。
		if ( ! function_exists( 'wp_handle_upload' ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
		}

		$uploaded = wp_handle_upload( $file, [
			'test_form' => false,
			'mimes'     => [
				'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
			],
		] );

		remove_filter( 'upload_dir', $upload_filter );

		if ( isset( $uploaded['error'] ) ) {
			return new \WP_Error( 'upload_error', $uploaded['error'], [ 'status' => 400 ] );
		}

		// submission_settings_json を更新
		$settings = $event['submission_settings'] ?? [];
		if ( is_string( $settings ) ) {
			$settings = json_decode( $settings, true ) ?: [];
		}
		$settings['template_file_path'] = $uploaded['file'];
		$settings['template_file_name'] = sanitize_file_name( $file['name'] );

		EventManager::instance()->update( $event_id, [
			'submission_settings' => $settings,
		] );

		return new \WP_REST_Response( [
			'success'       => true,
			'template_name' => $settings['template_file_name'],
		], 200 );
	}

	/**
	 * 演題投稿用Wordテンプレートを削除する
	 */
	public function delete_template( \WP_REST_Request $request ): \WP_REST_Response|\WP_Error {
		$event_id = (int) $request['id'];
		$event    = EventManager::instance()->get( $event_id );
		if ( null === $event ) {
			return new \WP_Error( 'not_found', __( 'Event not found.', 'conferencemanager' ), [ 'status' => 404 ] );
		}

		$settings = $event['submission_settings'] ?? [];
		if ( is_string( $settings ) ) {
			$settings = json_decode( $settings, true ) ?: [];
		}

		// ファイル削除
		if ( ! empty( $settings['template_file_path'] ) && file_exists( $settings['template_file_path'] ) ) {
			wp_delete_file( $settings['template_file_path'] );
		}

		unset( $settings['template_file_path'], $settings['template_file_name'] );

		EventManager::instance()->update( $event_id, [
			'submission_settings' => $settings,
		] );

		return new \WP_REST_Response( [ 'deleted' => true ], 200 );
	}

}
