<?php

namespace Devikit\Sellsy;

use Devikit\Sellsy\Api\Client;

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

/**
 * Sync WooCommerce customers to Sellsy companies / individuals.
 */
class CustomerSync {

	/**
	 * @var Client
	 */
	private $api_client;

	/**
	 * @param Client $api_client
	 */
	public function __construct( Client $api_client ) {
		$this->api_client = $api_client;
	}

	/**
	 * @param \WC_Order $order
	 * @return array{type:string,id:int}|\WP_Error
	 */
	public function get_or_create_customer( $order ) {
		$email = sanitize_email( (string) $order->get_billing_email() );
		if ( $email === '' ) {
			return new \WP_Error(
				'sellsy_missing_email',
				__( 'Billing email is required to sync the customer to Sellsy.', 'invoicing-integration-for-sellsy-and-woocommerce' )
			);
		}

		$is_company = $this->order_is_company( $order );

		$stored_type = (string) $order->get_meta( '_sellsy_related_type' );
		$stored_id   = absint( $order->get_meta( '_sellsy_related_id' ) );
		if ( $stored_id && in_array( $stored_type, [ 'company', 'individual' ], true ) ) {
			$related = [ 'type' => $stored_type, 'id' => $stored_id ];
			$this->ensure_address( $related, $order );
			return $related;
		}

		if ( $is_company ) {
			$found = $this->api_client->search_companies_by_email( $email );
		} else {
			$found = $this->api_client->search_individuals_by_email( $email );
		}

		if ( is_wp_error( $found ) ) {
			return $found;
		}

		if ( ! empty( $found[0]['id'] ) ) {
			$related = [
				'type' => $is_company ? 'company' : 'individual',
				'id'   => (int) $found[0]['id'],
			];
			$this->update_customer( $related, $order );
			$this->ensure_address( $related, $order );
			$this->store_related_meta( $order, $related );
			return $related;
		}

		$payload = $is_company ? $this->build_company_payload( $order ) : $this->build_individual_payload( $order );

		/**
		 * Filter Sellsy contact/company create payload.
		 *
		 * @param array     $payload
		 * @param \WC_Order $order
		 * @param bool      $is_company
		 */
		$payload = apply_filters( 'devikit_sellsy_contact_payload', $payload, $order, $is_company );

		$response = $is_company
			? $this->api_client->create_company( $payload )
			: $this->api_client->create_individual( $payload );

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		if ( empty( $response['id'] ) ) {
			return new \WP_Error(
				'sellsy_customer_create_failed',
				__( 'Sellsy did not return a customer ID.', 'invoicing-integration-for-sellsy-and-woocommerce' )
			);
		}

		$related = [
			'type' => $is_company ? 'company' : 'individual',
			'id'   => (int) $response['id'],
		];

		$this->ensure_address( $related, $order );
		$this->store_related_meta( $order, $related );

		return $related;
	}

	/**
	 * @param \WC_Order $order
	 * @return bool
	 */
	private function order_is_company( $order ) {
		$company = trim( (string) $order->get_billing_company() );
		if ( $company !== '' ) {
			return true;
		}

		$siret = preg_replace( '/\D+/', '', (string) $order->get_meta( '_billing_siret' ) );
		if ( $siret !== '' ) {
			return true;
		}

		$vat = $this->get_vat_number( $order );
		return $vat !== '';
	}

	/**
	 * @param \WC_Order $order
	 * @return string
	 */
	private function get_vat_number( $order ) {
		$candidates = [
			(string) $order->get_meta( '_billing_vat_number' ),
			(string) $order->get_meta( '_billing_vat' ),
			(string) $order->get_meta( '_billing_vat_id' ),
			(string) $order->get_meta( '_vat_number' ),
			(string) $order->get_meta( 'billing_vat_number' ),
			(string) $order->get_meta( 'vat_number' ),
		];

		foreach ( $candidates as $value ) {
			$value = strtoupper( preg_replace( '/\s+/', '', $value ) );
			if ( $value !== '' ) {
				return $value;
			}
		}

		return '';
	}

	/**
	 * @param \WC_Order $order
	 * @return array
	 */
	private function build_company_payload( $order ) {
		$name = trim( (string) $order->get_billing_company() );
		if ( $name === '' ) {
			$name = trim( $order->get_formatted_billing_full_name() );
		}
		if ( $name === '' ) {
			$name = (string) $order->get_billing_email();
		}

		$payload = [
			'name'  => $name,
			'type'  => 'client',
			'email' => sanitize_email( (string) $order->get_billing_email() ),
		];

		$phone = (string) $order->get_billing_phone();
		if ( $phone !== '' ) {
			$payload['phone_number'] = $phone;
		}

		$legal = [];
		$vat   = $this->get_vat_number( $order );
		if ( $vat !== '' ) {
			$legal['vat'] = $vat;
		}
		$siret = preg_replace( '/\D+/', '', (string) $order->get_meta( '_billing_siret' ) );
		if ( $siret !== '' ) {
			$legal['siret'] = $siret;
		}
		if ( $legal ) {
			$payload['legal_france'] = $legal;
		}

		return $payload;
	}

	/**
	 * @param \WC_Order $order
	 * @return array
	 */
	private function build_individual_payload( $order ) {
		$payload = [
			'type'       => 'client',
			'email'      => sanitize_email( (string) $order->get_billing_email() ),
			'first_name' => (string) $order->get_billing_first_name(),
			'last_name'  => (string) $order->get_billing_last_name(),
		];

		if ( $payload['last_name'] === '' ) {
			$payload['last_name'] = __( 'Customer', 'invoicing-integration-for-sellsy-and-woocommerce' );
		}

		$phone = (string) $order->get_billing_phone();
		if ( $phone !== '' ) {
			$payload['phone_number'] = $phone;
		}

		return $payload;
	}

	/**
	 * @param array{type:string,id:int} $related
	 * @param \WC_Order                 $order
	 */
	private function update_customer( array $related, $order ) {
		$payload = $related['type'] === 'company'
			? $this->build_company_payload( $order )
			: $this->build_individual_payload( $order );

		$payload = apply_filters( 'devikit_sellsy_contact_payload', $payload, $order, $related['type'] === 'company' );

		if ( $related['type'] === 'company' ) {
			$this->api_client->update_company( $related['id'], $payload );
		} else {
			$this->api_client->update_individual( $related['id'], $payload );
		}
	}

	/**
	 * @param array{type:string,id:int} $related
	 * @param \WC_Order                 $order
	 */
	private function ensure_address( array $related, $order ) {
		$line1 = trim( (string) $order->get_billing_address_1() );
		$city  = trim( (string) $order->get_billing_city() );
		$post  = trim( (string) $order->get_billing_postcode() );
		$cc    = strtoupper( (string) $order->get_billing_country() );

		if ( $line1 === '' || $city === '' || $post === '' || $cc === '' ) {
			return;
		}

		$payload = [
			'name'                 => __( 'Billing', 'invoicing-integration-for-sellsy-and-woocommerce' ),
			'address_line_1'       => $line1,
			'address_line_2'       => (string) $order->get_billing_address_2(),
			'postal_code'         => $post,
			'city'                 => $city,
			'country_code'         => $cc,
			'is_invoicing_address' => true,
			'is_delivery_address'  => true,
		];

		$result = $this->api_client->create_address( $related['type'], $related['id'], $payload );
		if ( is_wp_error( $result ) ) {
			$this->api_client->log( 'Address sync warning: ' . $result->get_error_message(), 'warning' );
		}
	}

	/**
	 * @param \WC_Order                 $order
	 * @param array{type:string,id:int} $related
	 */
	private function store_related_meta( $order, array $related ) {
		$order->update_meta_data( '_sellsy_related_type', $related['type'] );
		$order->update_meta_data( '_sellsy_related_id', (string) $related['id'] );
		$order->update_meta_data( '_sellsy_customer_id', (string) $related['id'] );
		$order->save();
	}
}
