<?php
/**
 * Import lich thang tu Excel (.xlsx) hoac CSV.
 *
 * @package DatvetaucaotocBooking
 */

declare(strict_types=1);

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

require_once DATVETAU_BOOKING_DIR . 'includes/class-trip-import-columns.php';
require_once DATVETAU_BOOKING_DIR . 'includes/lib/class-datvetau-xlsx-reader.php';

final class Datvetau_Booking_Trip_Importer {

	/**
	 * @return array{ok:int,errors:array<int,string>}
	 */
	public static function import_csv( string $csv_text, string $on_duplicate = 'update' ): array {
		$lines = preg_split( '/\r\n|\r|\n/', trim( $csv_text ) ) ?: array();
		if ( count( $lines ) < 2 ) {
			return array( 'ok' => 0, 'errors' => array( __( 'File trong hoac thieu dong du lieu.', 'datvetaucaotoc-booking' ) ) );
		}

		$header = str_getcsv( array_shift( $lines ) );
		$rows   = array( $header );
		foreach ( $lines as $line ) {
			if ( '' === trim( $line ) ) {
				continue;
			}
			$rows[] = str_getcsv( $line );
		}

		return self::import_table_rows( $rows, $on_duplicate );
	}

	/**
	 * @param array{name:string,tmp_name:string,type?:string,size?:int}|null $file $_FILES entry.
	 * @return array{ok:int,errors:array<int,string>}
	 */
	public static function import_uploaded_file( ?array $file, string $on_duplicate = 'update' ): array {
		if ( ! $file || empty( $file['tmp_name'] ) || ! is_uploaded_file( $file['tmp_name'] ) ) {
			return array( 'ok' => 0, 'errors' => array( __( 'Chua chon file.', 'datvetaucaotoc-booking' ) ) );
		}

		$name = strtolower( (string) ( $file['name'] ?? '' ) );
		$path = (string) $file['tmp_name'];

		if ( str_ends_with( $name, '.xlsx' ) ) {
			$parsed = Datvetau_Booking_Xlsx_Reader::read_first_sheet( $path );
			if ( ! $parsed['ok'] ) {
				return array( 'ok' => 0, 'errors' => array( $parsed['error'] ) );
			}
			if ( count( $parsed['rows'] ) < 2 ) {
				return array( 'ok' => 0, 'errors' => array( __( 'File Excel thieu dong du lieu.', 'datvetaucaotoc-booking' ) ) );
			}
			return self::import_table_rows( $parsed['rows'], $on_duplicate );
		}

		if ( str_ends_with( $name, '.csv' ) ) {
			$text = (string) file_get_contents( $path );
			return self::import_csv( $text, $on_duplicate );
		}

		return array(
			'ok'     => 0,
			'errors' => array( __( 'Chi ho tro file Excel (.xlsx) hoac CSV (.csv).', 'datvetaucaotoc-booking' ) ),
		);
	}

	/**
	 * @param array<int,array<int,string>> $table First row = header labels.
	 * @return array{ok:int,errors:array<int,string>}
	 */
	public static function import_table_rows( array $table, string $on_duplicate = 'update' ): array {
		if ( count( $table ) < 2 ) {
			return array( 'ok' => 0, 'errors' => array( __( 'File trong hoac thieu dong du lieu.', 'datvetaucaotoc-booking' ) ) );
		}

		$header_labels = array_map( static fn( $h ) => (string) $h, $table[0] );
		$mapped        = Datvetau_Booking_Trip_Import_Columns::map_header( $header_labels );
		if ( $mapped['errors'] ) {
			return array( 'ok' => 0, 'errors' => $mapped['errors'] );
		}
		$keys = $mapped['keys'];

		$ok     = 0;
		$errors = array();

		for ( $i = 1, $len = count( $table ); $i < $len; ++$i ) {
			$row_cells = $table[ $i ];
			if ( self::is_empty_row( $row_cells ) ) {
				continue;
			}

			$data = array();
			foreach ( $keys as $col_i => $key ) {
				if ( '' === $key ) {
					continue;
				}
				$data[ $key ] = isset( $row_cells[ $col_i ] ) ? trim( (string) $row_cells[ $col_i ] ) : '';
			}

			$line_num = $i + 1;
			$result   = self::import_data_row( $data, $line_num, $on_duplicate );
			if ( null === $result ) {
				continue;
			}
			if ( is_string( $result ) ) {
				$errors[] = $result;
				continue;
			}
			++$ok;
		}

		return array( 'ok' => $ok, 'errors' => $errors );
	}

	/**
	 * @param array<string,string> $data
	 * @return true|string|null true = saved, string = error, null = skipped duplicate
	 */
	private static function import_data_row( array $data, int $line_num, string $on_duplicate ) {
		$route = Datvetau_Booking_Route_Repository::find_by_slug( sanitize_title( (string) $data['route_slug'] ) );
		if ( ! $route ) {
			return sprintf(
				/* translators: 1: line number, 2: route slug */
				__( 'Dong %1$d: khong tim thay tuyen «%2$s» (xem slug o menu Tuyen).', 'datvetaucaotoc-booking' ),
				$line_num,
				$data['route_slug']
			);
		}

		$trip_date = self::normalize_date( (string) $data['trip_date'] );
		if ( ! $trip_date ) {
			return sprintf(
				/* translators: %d: line number */
				__( 'Dong %d: ngay chuyen khong hop le (dung dd/mm/yyyy hoac yyyy-mm-dd).', 'datvetaucaotoc-booking' ),
				$line_num
			);
		}

		$dep = self::normalize_time( (string) $data['departure_time'] );
		$arr = self::normalize_time( (string) $data['arrival_time'] );
		$seat = in_array( strtolower( (string) $data['seat_class'] ), array( 'eco', 'vip' ), true )
			? strtolower( (string) $data['seat_class'] )
			: 'eco';
		$capacity = max( 0, (int) preg_replace( '/\D/', '', (string) $data['capacity'] ) );
		$price        = (int) preg_replace( '/\D/', '', (string) $data['price_adult_vnd'] );
		$price_child  = (int) preg_replace( '/\D/', '', (string) ( $data['price_child_vnd'] ?? '0' ) );
		$price_senior = (int) preg_replace( '/\D/', '', (string) ( $data['price_senior_vnd'] ?? '0' ) );

		$existing = self::find_existing_trip( (int) $route['id'], $trip_date, $dep, $seat );

		$trip_row = array(
			'route_id'             => (int) $route['id'],
			'trip_date'            => $trip_date,
			'departure_time'       => $dep,
			'arrival_time'         => $arr,
			'operator_name'        => (string) $data['operator_name'],
			'operator_logo_url'    => esc_url_raw( (string) ( $data['operator_logo_url'] ?? '' ) ),
			'seat_class'           => $seat,
			'price_adult'          => $price,
			'price_adult_eco_base' => $price,
			'price_child'          => $price_child,
			'price_senior'         => $price_senior,
			'capacity'             => $capacity,
			'seats_remaining'      => $capacity,
			'status'               => 'active',
		);

		if ( $existing && 'skip' === $on_duplicate ) {
			return null;
		}

		if ( $existing && 'update' === $on_duplicate ) {
			$sold = (int) $existing['capacity'] - (int) $existing['seats_remaining'];
			$trip_row['seats_remaining'] = max( 0, $capacity - $sold );
			Datvetau_Booking_Trip_Repository::save( $trip_row, (int) $existing['id'] );
		} else {
			Datvetau_Booking_Trip_Repository::save( $trip_row, null );
		}

		return true;
	}

	/**
	 * @param array<int,string> $row
	 */
	private static function is_empty_row( array $row ): bool {
		foreach ( $row as $cell ) {
			if ( '' !== trim( (string) $cell ) ) {
				return false;
			}
		}
		return true;
	}

	private static function normalize_date( string $value ): ?string {
		$value = trim( $value );
		if ( '' === $value ) {
			return null;
		}
		if ( is_numeric( $value ) ) {
			return self::excel_serial_to_ymd( (float) $value );
		}
		if ( preg_match( '/^\d{4}-\d{2}-\d{2}$/', $value ) ) {
			return $value;
		}
		if ( preg_match( '/^(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})$/', $value, $m ) ) {
			$day   = (int) $m[1];
			$month = (int) $m[2];
			$year  = (int) $m[3];
			if ( checkdate( $month, $day, $year ) ) {
				return sprintf( '%04d-%02d-%02d', $year, $month, $day );
			}
			return null;
		}
		if ( preg_match( '/^(\d{2})-(\d{2})-(\d{4})$/', $value, $m ) ) {
			return $m[3] . '-' . $m[2] . '-' . $m[1];
		}
		return null;
	}

	private static function excel_serial_to_ymd( float $serial ): ?string {
		if ( $serial < 1 ) {
			return null;
		}
		$days = (int) floor( $serial );
		try {
			$base = new DateTimeImmutable( '1899-12-30' );
			$date = $base->modify( '+' . $days . ' days' );
			return $date->format( 'Y-m-d' );
		} catch ( Exception $e ) {
			return null;
		}
	}

	private static function normalize_time( string $value ): string {
		$value = trim( $value );
		if ( is_numeric( $value ) ) {
			$fraction = (float) $value;
			if ( $fraction >= 0 && $fraction < 1 ) {
				$seconds = (int) round( $fraction * 86400 );
				$h       = (int) floor( $seconds / 3600 );
				$m       = (int) floor( ( $seconds % 3600 ) / 60 );
				return sprintf( '%02d:%02d:00', $h, $m );
			}
		}
		if ( preg_match( '/^\d{1,2}:\d{2}$/', $value ) ) {
			return $value . ':00';
		}
		if ( preg_match( '/^\d{1,2}:\d{2}:\d{2}$/', $value ) ) {
			return $value;
		}
		return '00:00:00';
	}

	private static function find_existing_trip( int $route_id, string $trip_date, string $dep, string $seat ): ?array {
		global $wpdb;
		$table = Datvetau_Booking_Database::table( 'trips' );
		$row   = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$table} WHERE route_id = %d AND trip_date = %s AND departure_time = %s AND seat_class = %s LIMIT 1",
				$route_id,
				$trip_date,
				$dep,
				$seat
			),
			ARRAY_A
		);
		return $row ?: null;
	}

	/**
	 * Noi dung bang mau (header + dong vi du).
	 *
	 * @return array<int,array<int,string>>
	 */
	public static function sample_table_rows(): array {
		return array(
			Datvetau_Booking_Trip_Import_Columns::SAMPLE_HEADER_LABELS,
			array( 'rach-gia-phu-quoc', '06/10/2026', '12:00', '14:30', 'Phu Quoc Express', 'eco', '315000', '225000', '280000', '120' ),
			array( 'rach-gia-phu-quoc', '06/10/2026', '07:10', '09:40', 'Phu Quoc Express', 'eco', '315000', '225000', '280000', '80' ),
			array( 'phu-quoc-rach-gia', '07/10/2026', '12:00', '14:30', 'Phu Quoc Express', 'eco', '315000', '225000', '280000', '120' ),
		);
	}
}
