<?php

namespace MyListing\Ext\Maps;

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

abstract class Geocoder {
	public $platform;

	public function __construct() {
		$this->platform = mylisting()->maps()->platform;

		// Listen for location changes.
		add_action( 'mylisting/submission/save-listing-data', [ $this, 'frontend_update' ], 10, 2 );
		add_action( 'mylisting/admin/save-listing-data', [ $this, 'backend_update' ], 40, 2 );
	}

	/**
	 * Geocode location on listing submit/edit through the front-end forms.
	 *
	 * @since 1.7.2
	 */
	public function frontend_update( $listing_id, $fields ) {
		if ( empty( $fields['job_location'] ) || empty( $fields['job_location']['value'] ) ) {
			return;
		}

		if ( ! empty( $_POST['job_location__latitude'] ) && ! empty( $_POST['job_location__longitude'] ) ) {
			mlog( 'Skipping server-side address geocoding, data already passed through the frontend geocoder.' );
			return;
		}

		$this->save_location( $listing_id, $fields['job_location']['value'] );
	}

	/**
	 * Geocode address when listing is created/edited through wp-admin.
	 *
	 * @since 1.7.2
	 */
	public function backend_update( $listing_id, $listing ) {
		if ( ! is_admin() || empty( $_POST['job_location'] ) ) {
			return;
		}

		if ( ! empty( $_POST['job_location__latitude'] ) && ! empty( $_POST['job_location__longitude'] ) ) {
			mlog( 'Skipping server-side address geocoding, data already passed through the frontend geocoder.' );
			return;
		}

		$this->save_location( $listing_id, sanitize_text_field( $_POST['job_location'] ) );
	}

	public function geocode( $location ) {
		if ( ! is_string( $location ) || empty( trim( $location ) ) ) {
			return false;
		}

		$location = trim( $location );

		if ( ! ( $response = $this->client_geocode( $location ) ) ) {
			return false;
		}

		mlog( sprintf( 'Geocoding address through %s.', c27()->get_class_name( mylisting()->maps()->platform ) ) );
		$address = $this->transform_response( $response );

		return $address;
	}

	abstract public function client_geocode( $location );

	abstract public function transform_response( $response );

	public function save_location( $listing_id, $location ) {
		$this->clear_location_data( $listing_id );
		if ( ! ( $feature = $this->geocode( $location ) ) ) {
			mlog()->warn( sprintf( 'Server-side geocoding for location "%s" failed.', $location ) );
			return false;
		}

		mlog( 'Server-side location geocoding successful.' );
		update_post_meta( $listing_id, 'geolocation_lat', $feature['latitude'] );
		update_post_meta( $listing_id, 'geolocation_long', $feature['longitude'] );
		update_post_meta( $listing_id, 'geolocation_formatted_address', $feature['address'] );
		update_post_meta( $listing_id, 'geolocation_meta', $feature );
	}

	public function clear_location_data( $listing_id ) {
		// MyListing 1.7.2+ geolocation fields.
		delete_post_meta( $listing_id, 'geolocation_lat' );
		delete_post_meta( $listing_id, 'geolocation_long' );
		delete_post_meta( $listing_id, 'geolocation_formatted_address' );
		delete_post_meta( $listing_id, 'geolocation_meta' );

		// Old geolocation fields saved by WPJM (pre 1.7.2)
		delete_post_meta( $listing_id, 'geolocated' );
		delete_post_meta( $listing_id, 'geolocation_city' );
		delete_post_meta( $listing_id, 'geolocation_country_long' );
		delete_post_meta( $listing_id, 'geolocation_country_short' );
		delete_post_meta( $listing_id, 'geolocation_state_long' );
		delete_post_meta( $listing_id, 'geolocation_state_short' );
		delete_post_meta( $listing_id, 'geolocation_street' );
		delete_post_meta( $listing_id, 'geolocation_street_number' );
		delete_post_meta( $listing_id, 'geolocation_zipcode' );
		delete_post_meta( $listing_id, 'geolocation_postcode' );
	}
}