<?php
/**
 * Import FoodMaster.csv into ingredients table.
 *
 * @package RestaurantCosting
 */

declare(strict_types=1);

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

final class RC_Importer {

	public function get_default_csv_path(): string {
		return RC_PLUGIN_DIR . 'data/foodmaster.csv';
	}

	public function import_foodmaster_if_empty(): array {
		return $this->import_foodmaster_internal( $this->get_default_csv_path(), true );
	}
	
	public function import_foodmaster_manual( string $file_path ): array {
		return $this->import_foodmaster_internal( $file_path, false );
	}

	public function import_foodmaster_internal( string $file_path, bool $skip_existing = false ): array {
		if ( ! is_readable( $file_path ) ) {
			return array( 'imported' => 0, 'updated' => 0, 'skipped' => 0, 'errors' => 1, 'message' => 'File not readable.' );
		}

		$handle = fopen( $file_path, 'rb' );
		if ( false === $handle ) return array( 'imported' => 0, 'updated' => 0, 'skipped' => 0, 'errors' => 1, 'message' => 'Could not open CSV.' );

		$header = fgetcsv( $handle );
		if ( ! is_array( $header ) ) { fclose( $handle ); return array( 'imported' => 0, 'updated' => 0, 'skipped' => 0, 'errors' => 1, 'message' => 'Header missing.' ); }

		$map = $this->map_header( $header );
		$imported = 0; $updated = 0; $skipped = 0; $errors = 0;

		while ( ( $row = fgetcsv( $handle ) ) !== false ) {
			if ( RC_License::is_demo() ) {
				$current = RC_Ingredient_Repository::count();
				if ( $current >= 50 ) {
					$message = "Demo limit reached: stopped after {$imported} imported (50 max). Remaining rows skipped.";
					fclose( $handle );
					return array( 'imported' => $imported, 'updated' => $updated, 'skipped' => $skipped, 'errors' => $errors, 'message' => $message );
				}
			}
			if ( ! is_array( $row ) ) continue;
			$data = $this->row_to_ingredient( $row, $map );
			if ( '' === $data['name'] ) { ++$errors; continue; }

			$existing_id = RC_Name_Matcher::find_ingredient_id( $data['name'] );

			if ( $existing_id && $skip_existing ) {
				++$skipped;
				continue;
			}

			$result = RC_Ingredient_Repository::upsert( $data, $existing_id );

			if ( '' !== $data['food_type'] ) {
				RC_Food_Type_Repository::find_or_create( $data['food_type'] );
			}

			if ( '' !== $data['supplier'] ) {
				RC_Supplier_Repository::find_or_create( $data['supplier'] );
			}
			
			if ( $result['created'] ) ++$imported;
			elseif ( $result['updated'] ) ++$updated;
			else ++$errors;
		}
		fclose( $handle );

		$message = $skip_existing
			? "Import complete: $imported added, $skipped skipped (already exist)."
			: "Import complete: $imported added, $updated updated.";

		update_option( 'rc_last_foodmaster_import', array( 'at' => current_time( 'mysql' ), 'file' => basename( $file_path ), 'imported' => $imported, 'updated' => $updated, 'skipped' => $skipped, 'errors' => $errors ), false );
		return array( 'imported' => $imported, 'updated' => $updated, 'skipped' => $skipped, 'errors' => $errors, 'message' => $message );
	}

	private function map_header( array $header ): array {
		$map = array();
		foreach ( $header as $index => $label ) {
			$key = strtolower( trim( (string) $label ) );
			$key = str_replace( array( ' ', '(', ')' ), array( '_', '', '' ), $key );
			$aliases = array(
				'food' => 'name', 'foodtype' => 'food_type', 'size' => 'size_label',
				'weightgrams' => 'weight_grams', 'trans_fat' => 'trans_fat_grams',
				'sugar' => 'sugar', 'cost' => 'cost', 'carbgrams' => 'carb_grams',
				'fibergrams' => 'fiber_grams', 'cholestrol' => 'cholesterol_mg',
				'proteingrams' => 'protein_grams', 'foodcost' => 'food_cost',
				'package_size' => 'package_size', 'package_cost' => 'package_cost',
				'vita' => 'vit_a', 'vita_re' => 'vit_a', 'vita_reiu_div_10pt3' => 'vit_a',
				'vitc' => 'vit_c_mg', 'potassium' => 'potassium_mg',
				'iron_mg' => 'iron_mg', 'calcium' => 'calcium_mg',
				'ingredients' => 'ingredients_text',
			);
			if ( isset( $aliases[ $key ] ) ) $key = $aliases[ $key ];
			$map[ $key ] = (int) $index;
		}
		return $map;
	}

	private function row_to_ingredient( array $row, array $map ): array {
		$get = static function ( string $key ) use ( $row, $map ): string {
			return ( isset( $map[ $key ] ) && isset( $row[ $map[ $key ] ] ) ) ? trim( (string) $row[ $map[ $key ] ] ) : '';
		};

		$name = $get( 'name' );
		return array(
			'name'                => $name,
			'name_normalized'     => RC_Name_Matcher::normalize( $name ),
			'food_type'           => $get( 'food_type' ),
			'size_label'          => $get( 'size_label' ),
			'weight_grams'        => self::parse_number( $get( 'weight_grams' ) ),
			'calories'            => self::nullable_number( $get( 'calories' ) ),
			'fat_grams'           => self::nullable_number( $get( 'fat_grams' ) ),
			'saturated_fat_grams' => self::nullable_number( $get( 'saturated_fat_grams' ) ),
			'trans_fat_grams'     => self::nullable_number( $get( 'trans_fat_grams' ) ),
			'carb_grams'          => self::nullable_number( $get( 'carb_grams' ) ),
			'fiber_grams'         => self::nullable_number( $get( 'fiber_grams' ) ),
			'sugar_grams'         => self::nullable_number( $get( 'sugar' ) ?: $get( 'sugar_grams' ) ),
			'cholesterol_mg'      => self::nullable_number( $get( 'cholesterol_mg' ) ),
			'protein_grams'       => self::nullable_number( $get( 'protein_grams' ) ),
			'sodium_mg'           => self::nullable_number( $get( 'sodium' ) ),
			'vit_a'               => self::nullable_number( $get( 'vit_a' ) ),
			'vit_c_mg'            => self::nullable_number( $get( 'vit_c_mg' ) ),
			'potassium_mg'        => self::nullable_number( $get( 'potassium_mg' ) ),
			'calcium_mg'          => self::nullable_number( $get( 'calcium_mg' ) ),
			'iron_mg'             => self::nullable_number( $get( 'iron_mg' ) ),
			'ingredients_text'    => $get( 'ingredients_text' ) ?: null,
			'supplier'            => $get( 'supplier' ),
			'food_cost'           => self::parse_number( $get( 'food_cost' ) ),
			'package_size'        => $get( 'package_size' ),
			'package_cost'        => self::nullable_number( $get( 'cost' ) ),
		);
	}

	private static function parse_number( string $value ): float {
		$value = str_replace( array( ',', '$', ' ' ), '', $value );
		return ( '' === $value || ! is_numeric( $value ) ) ? 0.0 : (float) $value;
	}

	private static function nullable_number( string $value ): ?float {
		$value = str_replace( array( ',', '$', ' ' ), '', $value );
		return ( '' === $value || ! is_numeric( $value ) ) ? null : (float) $value;
	}
}
