<?php

namespace RadiusTheme\RadiusBooking\ExportImport\Exporters;

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

use RadiusTheme\RadiusBooking\ExportImport\Contracts\ExporterInterface;
use RadiusTheme\RadiusBooking\Models\User;
use RadiusTheme\RadiusBooking\Models\UserProfile;
use RadiusTheme\RadiusBooking\Models\EmployeeService;
use RadiusTheme\RadiusBooking\Models\EmployeeDayoff;
use RadiusTheme\RadiusBooking\Models\EmployeeWeekday;
use RadiusTheme\RadiusBooking\Models\EmployeeWeekdayTimePeriod;
use RadiusTheme\RadiusBooking\Models\EmployeeWeekdayTimePeriodService;
use RadiusTheme\RadiusBooking\Models\EmployeeWeekdayTimePeriodLocation;
use RadiusTheme\RadiusBooking\Models\EmployeeWeekdayBreakTime;
use RadiusTheme\RadiusBooking\Models\EmployeeSpecialDay;
use RadiusTheme\RadiusBooking\Models\EmployeeSpecialDayTimePeriod;
use RadiusTheme\RadiusBooking\Models\EmployeeSpecialDayTimePeriodService;
use RadiusTheme\RadiusBooking\Models\EmployeeSpecialDayTimePeriodLocation;

/**
 * Class StaffExporter
 *
 * Exports employees with all nested schedule data.
 *
 * @package RadiusTheme\RadiusBooking\ExportImport\Exporters
 */
class StaffExporter implements ExporterInterface {

	/**
	 * {@inheritDoc}
	 */
	public function getModuleName(): string {
		return 'staff';
	}

	/**
	 * {@inheritDoc}
	 */
	public function count(): int {
		return User::where( 'user_type', 'employee' )->count();
	}

	/**
	 * {@inheritDoc}
	 */
	public function export( int $offset = 0, int $limit = 500 ): array {
		$rows    = User::where( 'user_type', 'employee' )->offset( $offset )->limit( $limit )->get();
		$records = array();

		foreach ( $rows as $row ) {
			$user = User::hydrate( $row );
			$data = $user->toArray();

			// Remove sensitive data.
			unset( $data['password'], $data['token'] );

			$user_id = (int) $data['id'];

			// Profile.
			$data['profile'] = $this->exportProfile( $user_id );

			// Employee services.
			$data['services'] = $this->exportEmployeeServices( $user_id );

			// Days off.
			$data['days_off'] = $this->exportDaysOff( $user_id );

			// Weekdays with nested time periods.
			$data['weekdays'] = $this->exportWeekdays( $user_id );

			// Special days with nested time periods.
			$data['special_days'] = $this->exportSpecialDays( $user_id );

			$records[] = $data;
		}

		return $records;
	}

	/**
	 * Export user profile.
	 *
	 * @param int $user_id User ID.
	 *
	 * @return array|null
	 */
	private function exportProfile( int $user_id ): ?array {
		$row = UserProfile::where( 'user_id', $user_id )->first();
		if ( ! $row ) {
			return null;
		}
		$profile = UserProfile::hydrate( $row )->toArray();
		unset( $profile['id'] );
		return $profile;
	}

	/**
	 * Export employee service assignments.
	 *
	 * @param int $user_id User ID.
	 *
	 * @return array
	 */
	private function exportEmployeeServices( int $user_id ): array {
		$rows   = EmployeeService::where( 'user_id', $user_id )->get();
		$result = array();
		foreach ( $rows as $row ) {
			$item = EmployeeService::hydrate( $row )->toArray();
			unset( $item['id'] );
			$result[] = $item;
		}
		return $result;
	}

	/**
	 * Export employee days off.
	 *
	 * @param int $user_id User ID.
	 *
	 * @return array
	 */
	private function exportDaysOff( int $user_id ): array {
		$rows   = EmployeeDayoff::where( 'user_id', $user_id )->get();
		$result = array();
		foreach ( $rows as $row ) {
			$item = EmployeeDayoff::hydrate( $row )->toArray();
			unset( $item['id'] );
			$result[] = $item;
		}
		return $result;
	}

	/**
	 * Export weekdays with nested time periods, break times, and per-period services/locations.
	 *
	 * @param int $user_id User ID.
	 *
	 * @return array
	 */
	private function exportWeekdays( int $user_id ): array {
		$weekday_rows = EmployeeWeekday::where( 'user_id', $user_id )->get();
		$result       = array();

		foreach ( $weekday_rows as $wd_row ) {
			$weekday    = EmployeeWeekday::hydrate( $wd_row );
			$wd_data    = $weekday->toArray();
			$weekday_id = (int) $wd_data['id'];
			unset( $wd_data['id'] );

			// Time periods.
			$wd_data['time_periods'] = $this->exportWeekdayTimePeriods( $weekday_id );

			// Break times.
			$break_rows             = EmployeeWeekdayBreakTime::where( 'weekday_id', $weekday_id )->get();
			$wd_data['break_times'] = array();
			foreach ( $break_rows as $bt_row ) {
				$bt = EmployeeWeekdayBreakTime::hydrate( $bt_row )->toArray();
				unset( $bt['id'] );
				$wd_data['break_times'][] = $bt;
			}

			$result[] = $wd_data;
		}

		return $result;
	}

	/**
	 * Export weekday time periods with services and locations.
	 *
	 * @param int $weekday_id Weekday ID.
	 *
	 * @return array
	 */
	private function exportWeekdayTimePeriods( int $weekday_id ): array {
		$tp_rows = EmployeeWeekdayTimePeriod::where( 'weekday_id', $weekday_id )->get();
		$result  = array();

		foreach ( $tp_rows as $tp_row ) {
			$tp      = EmployeeWeekdayTimePeriod::hydrate( $tp_row );
			$tp_data = $tp->toArray();
			$tp_id   = (int) $tp_data['id'];
			unset( $tp_data['id'] );

			// Services for this time period.
			$svc_rows           = EmployeeWeekdayTimePeriodService::where( 'weekday_time_period_id', $tp_id )->get();
			$tp_data['services'] = array();
			foreach ( $svc_rows as $svc_row ) {
				$svc = EmployeeWeekdayTimePeriodService::hydrate( $svc_row )->toArray();
				unset( $svc['id'] );
				$tp_data['services'][] = $svc;
			}

			// Locations for this time period.
			$loc_rows            = EmployeeWeekdayTimePeriodLocation::where( 'weekday_time_period_id', $tp_id )->get();
			$tp_data['locations'] = array();
			foreach ( $loc_rows as $loc_row ) {
				$loc = EmployeeWeekdayTimePeriodLocation::hydrate( $loc_row )->toArray();
				unset( $loc['id'] );
				$tp_data['locations'][] = $loc;
			}

			$result[] = $tp_data;
		}

		return $result;
	}

	/**
	 * Export special days with nested time periods.
	 *
	 * @param int $user_id User ID.
	 *
	 * @return array
	 */
	private function exportSpecialDays( int $user_id ): array {
		$sd_rows = EmployeeSpecialDay::where( 'user_id', $user_id )->get();
		$result  = array();

		foreach ( $sd_rows as $sd_row ) {
			$sd      = EmployeeSpecialDay::hydrate( $sd_row );
			$sd_data = $sd->toArray();
			$sd_id   = (int) $sd_data['id'];
			unset( $sd_data['id'] );

			// Time periods.
			$tp_rows                  = EmployeeSpecialDayTimePeriod::where( 'special_day_id', $sd_id )->get();
			$sd_data['time_periods'] = array();

			foreach ( $tp_rows as $tp_row ) {
				$tp      = EmployeeSpecialDayTimePeriod::hydrate( $tp_row );
				$tp_data = $tp->toArray();
				$tp_id   = (int) $tp_data['id'];
				unset( $tp_data['id'] );

				// Services.
				$svc_rows            = EmployeeSpecialDayTimePeriodService::where( 'special_day_time_period_id', $tp_id )->get();
				$tp_data['services'] = array();
				foreach ( $svc_rows as $svc_row ) {
					$svc = EmployeeSpecialDayTimePeriodService::hydrate( $svc_row )->toArray();
					unset( $svc['id'] );
					$tp_data['services'][] = $svc;
				}

				// Locations.
				$loc_rows             = EmployeeSpecialDayTimePeriodLocation::where( 'special_day_time_period_id', $tp_id )->get();
				$tp_data['locations'] = array();
				foreach ( $loc_rows as $loc_row ) {
					$loc = EmployeeSpecialDayTimePeriodLocation::hydrate( $loc_row )->toArray();
					unset( $loc['id'] );
					$tp_data['locations'][] = $loc;
				}

				$sd_data['time_periods'][] = $tp_data;
			}

			$result[] = $sd_data;
		}

		return $result;
	}

	/**
	 * {@inheritDoc}
	 */
	public function getDependencies(): array {
		return array( 'service', 'location' );
	}
}
