<?php

namespace WPDRMS\ASP\Synonyms\Importers;

use Exception;
use WPDRMS\ASP\Synonyms\ORM\Synonym;
use WPDRMS\PluginCore\Traits\SingletonTrait;
use WPDRMS\Utils\MB;

defined('ABSPATH') || die("You can't access this file directly.");

class SynonymsJSONImporter {
	use SingletonTrait;

	/**
	 * Import synonyms from an uploaded file ($_FILES entry).
	 *
	 * @param array{name: string, tmp_name: string, error: int, size: int, type: string} $file
	 * @throws Exception
	 * @return int Number of rows imported
	 */
	public function importFromUploadedFile( array $file ): int {
		if ( $file['error'] !== UPLOAD_ERR_OK ) {
			throw new Exception(__('File upload failed.', 'ajax-search-pro'));
		}

		$contents = file_get_contents($file['tmp_name']); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
		if ( $contents === false || $contents === '' ) {
			throw new Exception(__('Could not read the uploaded file.', 'ajax-search-pro'));
		}

		$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
		return $this->importFromContent($contents, $ext);
	}

	/**
	 * Import synonyms from raw string content.
	 *
	 * @param string $content  Raw file contents (JSON or CSV)
	 * @param string $ext      File extension: 'json' or 'csv'
	 * @throws Exception
	 * @return int Number of rows imported
	 */
	public function importFromContent( string $content, string $ext = 'json' ): int {
		if ( $ext === 'csv' ) {
			$parsed = $this->parseCSV($content);
		} else {
			$parsed = $this->parseJSON($content);
		}

		if ( empty($parsed) ) {
			throw new Exception(__('No valid synonyms found in the file.', 'ajax-search-pro'));
		}

		return Synonym::bulkImportIgnore($parsed);
	}

	/**
	 * @return array<int, array{keyword: string, synonyms: string, lang: string}>
	 * @throws Exception
	 */
	private function parseJSON( string $content ): array {
		$decoded = json_decode(str_replace(array( "\r", "\n" ), '', trim($content)), true);

		if ( !is_array($decoded) ) {
			throw new Exception(__('Invalid JSON file content.', 'ajax-search-pro'));
		}

		$parsed = array();
		foreach ( $decoded as $row ) {
			$keyword  = $this->normalizeKeyword((string) ( $row['keyword'] ?? '' ));
			$synonyms = $this->normalizeKeyword((string) ( $row['synonyms'] ?? '' ));
			$lang     = $this->normalizeKeyword((string) ( $row['lang'] ?? '' ));

			if ( $keyword !== '' && $synonyms !== '' ) {
				$parsed[] = array(
					'keyword'  => $keyword,
					'synonyms' => $synonyms,
					'lang'     => $lang,
				);
			}
		}

		return $parsed;
	}

	/**
	 * @return array<int, array{keyword: string, synonyms: string, lang: string}>
	 */
	private function parseCSV( string $content ): array {
		$parsed = array();
		$lines  = str_getcsv($content, "\n");

		foreach ( $lines as $line ) {
			$data = str_getcsv((string) $line);
			if ( empty($data) || !isset($data[0]) ) {
				continue;
			}

			$keyword  = $this->normalizeKeyword((string) $data[0]);
			$synonyms = array_values(array_filter(
				array_slice($data, 1),
				fn ( $v ) => is_string($v) && $v !== ''
			));

			if ( $keyword !== '' && !empty($synonyms) ) {
				$parsed[] = array(
					'keyword'  => $keyword,
					'synonyms' => implode(',', array_map(array( $this, 'normalizeKeyword' ), $synonyms)),
					'lang'     => '',
				);
			}
		}

		return $parsed;
	}

	private function normalizeKeyword( string $keyword ): string {
		return (string) preg_replace('/\s+/', ' ', MB::strtolower(trim($keyword)));
	}
}
