<?php

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

class GDATTFront {
	private $edit_mode = false;
	private $icons = array(
		'code'       => 'c|cc|h|js|class',
		'xml'        => 'xml',
		'excel'      => 'xla|xls|xlsx|xlt|xlw|xlam|xlsb|xlsm|xltm',
		'word'       => 'docx|dotx|docm|dotm',
		'image'      => 'png|gif|jpg|jpeg|jpe|jp|bmp|tif|tiff|svg|webp|heic',
		'psd'        => 'psd',
		'ai'         => 'ai',
		'archive'    => 'zip|rar|gz|gzip|tar',
		'text'       => 'txt|asc|nfo',
		'powerpoint' => 'pot|pps|ppt|pptx|ppam|pptm|sldm|ppsm|potm',
		'pdf'        => 'pdf',
		'html'       => 'htm|html|css',
		'video'      => 'avi|asf|asx|wax|wmv|wmx|divx|flv|mov|qt|mpeg|mpg|mpe|mp4|m4v|ogv|mkv',
		'documents'  => 'odt|odp|ods|odg|odc|odb|odf|wp|wpd|rtf',
		'audio'      => 'mp3|m4a|m4b|mp4|m4v|wav|ra|ram|ogg|oga|mid|midi|wma|mka',
		'icon'       => 'ico',
	);

	public function __construct() {
		add_action( 'bbp_init', array( $this, 'load' ) );
	}

	public static function instance() {
		static $instance = false;

		if ( $instance === false ) {
			$instance = new GDATTFront();
		}

		return $instance;
	}

	public function load() {
		add_action( 'wp_enqueue_scripts', array( $this, 'wp_enqueue_scripts' ) );

		add_action( 'bbp_theme_before_reply_form_submit_wrapper', array( $this, 'embed_form' ) );
		add_action( 'bbp_theme_before_topic_form_submit_wrapper', array( $this, 'embed_form' ) );

		add_action( 'bbp_edit_reply', array( $this, 'edit_reply' ), 10, 5 );
		add_action( 'bbp_edit_topic', array( $this, 'edit_topic' ), 10, 4 );
		add_action( 'bbp_new_reply', array( $this, 'save_reply' ), 10, 5 );
		add_action( 'bbp_new_topic', array( $this, 'save_topic' ), 10, 4 );

		add_filter( 'bbp_get_reply_content', array( $this, 'embed_attachments' ), 100, 2 );
		add_filter( 'bbp_get_topic_content', array( $this, 'embed_attachments' ), 100, 2 );

		if ( d4p_bba_o( 'attachment_icon' ) == 1 ) {
			add_action( 'bbp_theme_before_topic_title', array( $this, 'show_attachments_icon' ) );
		}

		$this->register_scripts_and_styles();
	}

	private function icon( $ext ) : string {
		foreach ( $this->icons as $icon => $list ) {
			$list = explode( '|', $list );

			if ( in_array( $ext, $list ) ) {
				return $icon;
			}
		}

		return 'generic';
	}

	public function register_scripts_and_styles() {
		$debug = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG;
		$files = 'front' . ( $debug ? '' : '.min' );

		wp_register_style( 'gdatt-attachments', GDBBPRESSATTACHMENTS_URL . 'css/' . $files . '.css', array(), GDBBPRESSATTACHMENTS_VERSION );
		wp_register_script( 'gdatt-attachments', GDBBPRESSATTACHMENTS_URL . 'js/' . $files . '.js', array( 'jquery' ), GDBBPRESSATTACHMENTS_VERSION, true );
	}

	public function include_scripts_and_styles() {
		wp_enqueue_style( 'gdatt-attachments' );
		wp_enqueue_script( 'gdatt-attachments' );

		wp_localize_script( 'gdatt-attachments', 'gdbbPressAttachmentsInit', array(
			'max_files'    => apply_filters( 'd4p_bbpressattchment_allow_upload', GDATTCore::instance()->get_max_files(), bbp_get_forum_id() ),
			'are_you_sure' => esc_html__( 'This operation is not reversible. Are you sure?', 'gd-bbpress-attachments' ),
		) );
	}

	public function wp_enqueue_scripts() {
		if ( d4p_bba_o( 'include_always' ) == 1 || d4p_is_bbpress() ) {
			$this->include_scripts_and_styles();
		}
	}

	public function edit_topic( $topic_id, $forum_id, $anonymous_data, $topic_author ) {
		$this->edit_mode = true;
		$this->process_attachments( 0, $topic_id, $forum_id, $anonymous_data, $topic_author );
	}

	public function edit_reply( $reply_id, $topic_id, $forum_id, $anonymous_data = null, $reply_author = null ) {
		$this->edit_mode = true;
		$this->process_attachments( $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author );
	}

	public function save_topic( $topic_id, $forum_id, $anonymous_data, $topic_author ) {
		$this->edit_mode = false;
		$this->process_attachments( 0, $topic_id, $forum_id, $anonymous_data, $topic_author );
	}

	public function save_reply( $reply_id, $topic_id, $forum_id, $anonymous_data = null, $reply_author = null ) {
		$this->edit_mode = false;
		$this->process_attachments( $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author );
	}

	public function process_attachments( $reply_id, $topic_id, $forum_id, $anonymous_data = null, $reply_author = null ) {
		$uploads  = array();
		$revision = false;

		if ( ! empty( $_FILES ) && ! empty( $_FILES['d4p_attachment'] ) ) { //phpcs:ignore 	WordPress.Security.NonceVerification.Missing
			require_once( ABSPATH . 'wp-admin/includes/file.php' );

			$errors    = new gdbbp_Error();
			$overrides = array( 'test_form' => false, 'upload_error_handler' => 'd4p_bbattachment_handle_upload_error' );

			foreach ( $_FILES['d4p_attachment']['error'] as $key => $error ) { //phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
				$file_name = $_FILES['d4p_attachment']['name'][ $key ]; //phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized

				if ( $error == UPLOAD_ERR_OK ) {
					$file = array(
						'name'     => $file_name,
						'type'     => $_FILES['d4p_attachment']['type'][ $key ], //phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
						'size'     => $_FILES['d4p_attachment']['size'][ $key ], //phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
						'tmp_name' => $_FILES['d4p_attachment']['tmp_name'][ $key ], //phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
						'error'    => $_FILES['d4p_attachment']['error'][ $key ], //phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
					);

					$file_name = sanitize_file_name( $file_name );

					if ( GDATTCore::instance()->is_right_size( $file, $forum_id ) ) {
						$upload = wp_handle_upload( $file, $overrides );

						if ( ! is_wp_error( $upload ) ) {
							$uploads[] = $upload;
						} else {
							$errors->add( 'wp_upload', $upload->errors['wp_upload_error'][0], $file_name );
						}
					} else {
						$errors->add( 'd4p_upload', 'File exceeds allowed file size.', $file_name );
					}
				} else {
					switch ( $error ) {
						default:
						case 'UPLOAD_ERR_NO_FILE':
							$errors->add( 'php_upload', 'File not uploaded.', $file_name );
							break;
						case 'UPLOAD_ERR_INI_SIZE':
							$errors->add( 'php_upload', 'Upload file size exceeds PHP maximum file size allowed.', $file_name );
							break;
						case 'UPLOAD_ERR_FORM_SIZE':
							$errors->add( 'php_upload', 'Upload file size exceeds FORM specified file size.', $file_name );
							break;
						case 'UPLOAD_ERR_PARTIAL':
							$errors->add( 'php_upload', 'Upload file only partially uploaded.', $file_name );
							break;
						case 'UPLOAD_ERR_CANT_WRITE':
							$errors->add( 'php_upload', 'Can\'t write file to the disk.', $file_name );
							break;
						case 'UPLOAD_ERR_NO_TMP_DIR':
							$errors->add( 'php_upload', 'Temporary folder for upload is missing.', $file_name );
							break;
						case 'UPLOAD_ERR_EXTENSION':
							$errors->add( 'php_upload', 'Server extension restriction stopped upload.', $file_name );
							break;
					}
				}
			}
		}

		$post_id = $reply_id == 0 ? $topic_id : $reply_id;

		if ( ! empty( $errors->errors ) && d4p_bba_o( 'log_upload_errors' ) == 1 ) {
			foreach ( $errors->errors as $code => $errs ) {
				foreach ( $errs as $error ) {
					if ( $error[0] != '' && $error[1] != '' ) {
						add_post_meta( $post_id, '_bbp_attachment_upload_error', array(
								'code'    => $code,
								'file'    => $error[1],
								'message' => $error[0],
							)
						);
					}
				}
			}

			$revision = true;
		}

		if ( ! empty( $uploads ) ) {
			require_once( ABSPATH . 'wp-admin/includes/media.php' );
			require_once( ABSPATH . 'wp-admin/includes/image.php' );

			foreach ( $uploads as $upload ) {
				$wp_filetype = wp_check_filetype( basename( $upload['file'] ) );
				$attachment  = array(
					'post_mime_type' => $wp_filetype['type'],
					'post_title'     => preg_replace( '/\.[^.]+$/', '', basename( $upload['file'] ) ),
					'post_content'   => '',
					'post_status'    => 'inherit',
				);

				$attach_id   = wp_insert_attachment( $attachment, $upload['file'], $post_id );
				$attach_data = wp_generate_attachment_metadata( $attach_id, $upload['file'] );

				wp_update_attachment_metadata( $attach_id, $attach_data );
				update_post_meta( $attach_id, '_bbp_attachment', '1' );
			}

			$revision = true;
		}

		if ( $this->edit_mode && $revision ) {
			add_filter( 'wp_save_post_revision_post_has_changed', array( $this, 'post_has_changed' ) );
		}
	}

	public function post_has_changed() : bool {
		remove_filter( 'wp_save_post_revision_post_has_changed', array( $this, 'post_has_changed' ) );

		return true;
	}

	public function show_attachments_icon() {
		$topic_id = bbp_get_topic_id();
		$count    = d4p_topic_attachments_count( $topic_id, true );

		if ( $count > 0 ) {
			echo '<span class="bbp-attachments-count" title="' . $count . ' ' . _n( 'attachment', 'attachments', $count, 'gd-bbpress-attachments' ) . '"></span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		}
	}

	public function embed_attachments( $content, $id ) {
		global $user_ID;

		$attachments = d4p_get_post_attachments( $id );

		$post      = get_post( $id );
		$author_id = $post->post_author;

		if ( ! empty( $attachments ) ) {
			$content .= '<div class="bbp-attachments">';
			$content .= '<h6>' . __( 'Attachments', 'gd-bbpress-attachments' ) . ':</h6>';

			if ( ! is_user_logged_in() && GDATTCore::instance()->is_hidden_from_visitors() ) {
				$login_url = apply_filters( 'd4p_bbpressattchment_login_url', wp_login_url( get_permalink() ), $post );

				/* translators: 1: Replaced with Login URL. */
				$content .= sprintf( __( 'You must be <a href=\'%s\'>logged in</a> to view attached files.', 'gd-bbpress-attachments' ), $login_url );
			} else {
				$listing    = '<ol';
				$thumbnails = '<ol';

				if ( d4p_bba_o( "attachment_icons" ) == 1 ) {
					$listing    .= ' class="with-icons d4p-bbp-listing"';
					$thumbnails .= ' class="with-icons d4p-bba-thumbnails"';
				} else {
					$listing    .= ' class="d4p-bbp-listing"';
					$thumbnails .= ' class="d4p-bba-thumbnails"';
				}

				$listing    .= '>';
				$thumbnails .= '>';
				$images     = $files = 0;

				foreach ( $attachments as $attachment ) {
					$actions = array();

					$url = add_query_arg( '_wpnonce', wp_create_nonce( 'd4p-bbpress-attachments' ) );
					$url = add_query_arg( 'att_id', $attachment->ID, $url );
					$url = add_query_arg( 'bbp_id', $id, $url );

					$allow = 'no';
					if ( d4p_is_user_admin() ) {
						$allow = d4p_bba_o( 'delete_visible_to_admins' );
					} else if ( d4p_is_user_moderator() ) {
						$allow = d4p_bba_o( 'delete_visible_to_moderators' );
					} else if ( $author_id == $user_ID ) {
						$allow = d4p_bba_o( 'delete_visible_to_author' );
					}

					if ( $allow == 'delete' || $allow == 'both' ) {
						$actions[] = '<a class="d4p-bba-action-delete" href="' . esc_url( add_query_arg( 'd4pbbaction', 'delete', $url ) ) . '">' . esc_html__( 'delete', 'gd-bbpress-attachments' ) . '</a>';
					}

					if ( $allow == 'detach' || $allow == 'both' ) {
						$actions[] = '<a class="d4p-bba-action-detach" href="' . esc_url( add_query_arg( 'd4pbbaction', 'detach', $url ) ) . '">' . esc_html__( 'detach', 'gd-bbpress-attachments' ) . '</a>';
					}

					if ( count( $actions ) > 0 ) {
						$actions = ' <span class="d4p-bba-actions">[' . join( ' | ', $actions ) . ']</span>';
					} else {
						$actions = '';
					}

					$file     = get_attached_file( $attachment->ID );
					$ext      = pathinfo( $file, PATHINFO_EXTENSION );
					$filename = pathinfo( $file, PATHINFO_BASENAME );
					$file_url = wp_get_attachment_url( $attachment->ID );

					$html    = $class_li = $class_span = $class_a = $rel_a = "";
					$a_title = $filename;
					$caption = false;

					$img = false;
					if ( d4p_bba_o( 'image_thumbnail_active' ) == 1 ) {
						$html = wp_get_attachment_image( $attachment->ID, 'd4p-bbp-thumb' );

						if ( $html != '' ) {
							$img = true;

							$class_li = 'bbp-atthumb';

							if ( d4p_bba_o( 'image_thumbnail_inline' ) == 1 ) {
								$class_li .= ' bbp-inline';
							}

							$class_a = d4p_bba_o( 'image_thumbnail_css' );
							$caption = d4p_bba_o( 'image_thumbnail_caption' ) == 1;

							$rel_a = ' rel="' . esc_attr( d4p_bba_o( 'image_thumbnail_rel' ) ) . '"';
							$rel_a = str_replace( '%ID%', $id, $rel_a );
							$rel_a = str_replace( '%TOPIC%', bbp_get_topic_id(), $rel_a );
						}
					}

					$item_class = 'd4p-bbp-attachment d4p-bbp-attachment-' . $ext . ' ' . $class_li;

					$item = '<li id="d4p-bbp-attachment_' . esc_attr( $attachment->ID ) . '" class="' . esc_attr( sanitize_html_class( $item_class ) ) . '">';

					if ( $html == '' ) {
						$html = $filename;

						if ( d4p_bba_o( "attachment_icons" ) == 1 ) {
							$class_span = "bbp-atticon bbp-atticon-" . $this->icon( $ext );
						}
					}

					if ( $img ) {
						if ( $caption ) {
							$item .= '<div style="width: ' . esc_attr( d4p_bba_o( "image_thumbnail_size_x" ) ) . 'px" class="wp-caption">';
						}

						$item .= '<a class="' . esc_attr( sanitize_html_class( $class_a ) ) . '"' . $rel_a . ' href="' . esc_url( $file_url ) . '" title="' . esc_attr( $a_title ) . '">' . $html . '</a>';

						if ( $caption ) {
							$a_title = '<a href="' . esc_url( $file_url ) . '" download>' . $a_title . '</a>';

							$item .= '<p class="wp-caption-text">' . $a_title . '<br/>' . $actions . '</p></div>';
						}
					} else {
						$item .= '<span role="presentation" class="' . esc_attr( sanitize_html_class( $class_span ) ) . '"></span> ';
						$item .= '<div class="d4p-bbp-att-wrapper"><a class="' . esc_attr( sanitize_html_class( $class_a ) ) . '"' . $rel_a . ' href="' . esc_url( $file_url ) . '" title="' . esc_attr( $a_title ) . '" download>' . $html . '</a>' . $actions . '</div>';
					}

					$item .= '</li>';

					if ( $img ) {
						$thumbnails .= $item;
						$images ++;
					} else {
						$listing .= $item;
						$files ++;
					}
				}

				$thumbnails .= '</ol>';
				$listing    .= '</ol>';

				if ( $images > 0 ) {
					$content .= $thumbnails;
				}

				if ( $files > 0 ) {
					$content .= $listing;
				}
			}

			$content .= '</div>';
		}

		if ( ( d4p_bba_o( 'errors_visible_to_author' ) == 1 && $author_id == $user_ID ) || ( d4p_bba_o( 'errors_visible_to_admins' ) == 1 && d4p_is_user_admin() ) || ( d4p_bba_o( 'errors_visible_to_moderators' ) == 1 && d4p_is_user_moderator() ) ) {
			$errors = get_post_meta( $id, '_bbp_attachment_upload_error' );

			if ( ! empty( $errors ) ) {
				$content .= '<div class="bbp-attachments-errors">';
				$content .= '<h6>' . __( 'Upload Errors', 'gd-bbpress-attachments' ) . ':</h6>';
				$content .= '<ol';

				$class_li = 'bbp-file-error';
				if ( d4p_bba_o( "attachment_icons" ) == 1 ) {
					$content  .= ' class="with-icons"';
					$class_li .= ' bbp-atticon bbp-atticon-error';
				}

				$content .= '>';

				foreach ( $errors as $error ) {
					$content .= '<li class="' . esc_attr( sanitize_html_class( $class_li ) ) . '"><span role="presentation" class="' . esc_attr( sanitize_html_class( $class_li ) ) . '"></span> ';
					$content .= '<div class="d4p-bbp-att-wrapper"><strong>' . esc_html( $error['file'] ) . '</strong>: ' . esc_html__( $error["message"], "gd-bbpress-attachments" ) . '</div></li>'; //phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
				}

				$content .= '</ol></div>';
			}
		}

		return $content;
	}

	public function embed_form() {
		$can_upload = apply_filters( 'd4p_bbpressattchment_allow_upload', GDATTCore::instance()->is_user_allowed(), d4p_get_forum_id() );
		if ( ! $can_upload ) {
			return;
		}

		$is_enabled = apply_filters( 'd4p_bbpressattchment_forum_enabled', GDATTCore::instance()->enabled_for_forum(), d4p_get_forum_id() );
		if ( ! $is_enabled ) {
			return;
		}

		$file_size = apply_filters( 'd4p_bbpressattchment_max_file_size', GDATTCore::instance()->get_file_size(), d4p_get_forum_id() );

		include( GDBBPRESSATTACHMENTS_PATH . 'forms/uploader.php' );
	}
}

$d4p_upload_error_messages = array(
	__( 'File exceeds allowed file size.', 'gd-bbpress-attachments' ),
	__( 'File not uploaded.', 'gd-bbpress-attachments' ),
	__( 'Upload file size exceeds PHP maximum file size allowed.', 'gd-bbpress-attachments' ),
	__( 'Upload file size exceeds FORM specified file size.', 'gd-bbpress-attachments' ),
	__( 'Upload file only partially uploaded.', 'gd-bbpress-attachments' ),
	__( 'Can\'t write file to the disk.', 'gd-bbpress-attachments' ),
	__( 'Temporary folder for upload is missing.', 'gd-bbpress-attachments' ),
	__( 'Server extension restriction stopped upload.', 'gd-bbpress-attachments' ),
);
