<?php

namespace VendorTasksDokanClickUp\API;

use VendorTasksDokanClickUp\Settings\PluginSettings;
use WeDevs\Dokan\Vendor\Vendor;

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

/**
 * Vendor Task Formatter
 *
 * Pure PHP — no HTTP, no caching. Builds the task data array from vendor
 * user data and plugin settings. Testable without a ClickUp connection.
 *
 * @since 1.4.0
 * @package VendorTasksDokanClickUp
 * @subpackage API
 */
class VendorTaskFormatter {

	/**
	 * Build task data for a vendor.
	 *
	 * Builds task data from global settings, overriding individual fields with
	 * values from event_templates[$event_key] when they are set. Pass
	 * 'vendor_registered' (default) to use the global defaults unchanged.
	 *
	 * @since 1.4.0
	 *
	 * @param int    $vendor_id Vendor user ID.
	 * @param string $event_key Event template key (default: 'vendor_registered').
	 * @return array<string, mixed> Formatted task data, or empty array if vendor not found.
	 */
	public function format( int $vendor_id, string $event_key = 'vendor_registered' ): array {
		$wp_user = get_userdata( $vendor_id );
		if ( ! $wp_user ) {
			return array();
		}

		// Resolve vendor data — use Dokan Vendor object when available, fall back to WP user.
		$vendor    = function_exists( 'dokan' ) ? dokan()->vendor->get( $vendor_id ) : null;
		$is_vendor = $vendor instanceof Vendor;

		$email       = $is_vendor ? ( $vendor->get_email() ?: $wp_user->user_email ) : $wp_user->user_email;
		$shop_name   = $is_vendor ? ( $vendor->get_shop_name() ?: '' ) : '';
		$shop_url    = $is_vendor ? ( $vendor->get_shop_url() ?: '' ) : '';
		$phone       = $is_vendor ? ( $vendor->get_phone() ?: '' ) : '';
		$address     = $is_vendor ? ( $vendor->get_address() ?: array() ) : array();
		$socials     = $is_vendor ? ( (array) ( $vendor->get_social_profiles() ?: array() ) ) : array();
		$is_trusted  = $is_vendor && $vendor->is_trusted();
		$toc_enabled = $is_vendor && $vendor->toc_enabled();

		if ( $is_vendor && ( ! empty( $vendor->get_first_name() ) || ! empty( $vendor->get_last_name() ) ) ) {
			$full_name = trim( $vendor->get_first_name() . ' ' . $vendor->get_last_name() );
		} else {
			$full_name = $wp_user->display_name;
		}

		$ps        = new PluginSettings();
		$event_tpl = $ps->get_event_template( $event_key );

		$task_name_format = ( $event_tpl['name_format'] ?? '' ) ?: $ps->get_task_name_format();
		$description_type = ( $event_tpl['description_type'] ?? '' ) ?: $ps->get_task_description_type();
		$custom_template  = ( $event_tpl['description_template'] ?? '' ) ?: $ps->get_description_template();
		$priority_tpl     = (int) ( $event_tpl['priority'] ?? 0 );
		$priority         = $priority_tpl > 0 ? $priority_tpl : $ps->get_task_priority();
		$task_status      = ( $event_tpl['status'] ?? '' ) ?: $ps->get_task_status();
		$due_offset_tpl   = isset( $event_tpl['due_date_offset'] ) ? (int) $event_tpl['due_date_offset'] : -1;
		$due_offset       = $due_offset_tpl >= 0 ? $due_offset_tpl : $ps->get_task_due_date_offset();

		$task_name = str_replace(
			array( '{vendor_name}', '{vendor_email}', '{shop_name}' ),
			array(
				sanitize_text_field( $full_name ),
				sanitize_text_field( $email ),
				sanitize_text_field( ! empty( $shop_name ) ? $shop_name : 'N/A' ),
			),
			$task_name_format
		);

		// Build description — custom template takes priority over built-in formatters
		if ( ! empty( $custom_template ) ) {
			$description = $this->apply_description_template( $custom_template, $vendor_id, $full_name, $email, $shop_name, $shop_url, $phone, $address, $socials, $is_trusted, $toc_enabled );
		} elseif ( 'markdown' === $description_type ) {
			$description = $this->format_markdown_description( $vendor_id, $full_name, $email, $shop_name, $shop_url, $phone, $address, $socials, $is_trusted, $toc_enabled );
		} else {
			$description = $this->format_normal_description( $vendor_id, $full_name, $email, $shop_name, $shop_url, $phone, $address, $socials, $is_trusted, $toc_enabled );
		}

		$description_key = ( 'markdown' === $description_type ) ? 'markdown_content' : 'description';

		$task = array(
			'name'           => $task_name,
			$description_key => $description,
			'tags'           => array( 'vendor-registration', 'dokan' ),
			'priority'       => $priority,
		);

		if ( ! empty( $task_status ) ) {
			$task['status'] = $task_status;
		}

		$assignees = $ps->get_task_assignees();
		if ( ! empty( $assignees ) ) {
			$task['assignees'] = $assignees;
		}

		if ( $due_offset > 0 ) {
			// ClickUp requires millisecond Unix timestamp
			$task['due_date']      = ( time() + ( $due_offset * DAY_IN_SECONDS ) ) * 1000;
			$task['due_date_time'] = false;
		}

		/* @var array<string, mixed> $task */
		$task = apply_filters( 'vendor_tasks_dokan_clickup_task_data', $task, $vendor_id, $event_key );
		return $task;
	}

	/**
	 * Apply a custom description template with placeholder substitution
	 *
	 * @since 1.4.0
	 *
	 * @param string $template     Template string with {placeholder} tokens.
	 * @param int    $vendor_id    Vendor user ID.
	 * @param string $full_name    Vendor full name.
	 * @param string $email        Vendor email.
	 * @param string $shop_name    Vendor shop name.
	 * @param string $shop_url     Vendor store URL.
	 * @param string $phone        Vendor phone.
	 * @param array  $address      Vendor address array.
	 * @param array  $socials      Social profile URLs keyed by platform.
	 * @param bool   $is_trusted   Whether vendor is trusted.
	 * @param bool   $toc_enabled  Whether vendor accepted T&C.
	 * @return string Rendered description.
	 */
	private function apply_description_template( string $template, int $vendor_id, string $full_name, string $email, string $shop_name, string $shop_url, string $phone, array $address, array $socials = array(), bool $is_trusted = false, bool $toc_enabled = false ): string {
		$vendor = function_exists( 'dokan' ) ? dokan()->vendor->get( $vendor_id ) : null;

		$location_parts = $this->get_address( $address );
		$full_address   = implode( ', ', $location_parts );

		// Store hours / vacation data from dokan_profile_settings (F-25)
		$dokan_meta        = get_user_meta( $vendor_id, 'dokan_profile_settings', true );
		$dokan_meta        = is_array( $dokan_meta ) ? $dokan_meta : array();
		$store_hours_on    = ! empty( $dokan_meta['dokan_store_time_enabled'] ) ? __( 'Yes', 'alamin-vendor-tasks-dokan-clickup' ) : __( 'No', 'alamin-vendor-tasks-dokan-clickup' );
		$store_open_notice = sanitize_text_field( $dokan_meta['dokan_store_open_close_notice'] ?? '' );

		$social_parts = $this->format_social_profiles( $socials );

		$placeholders = array(
			'{vendor_name}'         => sanitize_text_field( $full_name ),
			'{vendor_email}'        => sanitize_email( $email ),
			'{shop_name}'           => sanitize_text_field( $shop_name ?: 'N/A' ),
			'{shop_url}'            => esc_url( $shop_url ),
			'{vendor_phone}'        => sanitize_text_field( $phone ?: '' ),
			'{vendor_address}'      => $full_address,
			'{vendor_city}'         => sanitize_text_field( $address['city'] ?? '' ),
			'{vendor_country}'      => sanitize_text_field( $address['country'] ?? '' ),
			'{registration_date}'   => $vendor instanceof Vendor ? esc_html( $vendor->get_register_date() ?? '' ) : '',
			'{admin_url}'           => $vendor instanceof Vendor ? esc_url( $vendor->get_profile_url() ) : '',
			'{user_id}'             => (string) absint( $vendor_id ),
			'{store_hours_enabled}' => $store_hours_on,
			'{store_open_notice}'   => $store_open_notice,
			'{social_profiles}'     => implode( ', ', $social_parts ),
			'{is_trusted}'          => $is_trusted ? __( 'Yes', 'alamin-vendor-tasks-dokan-clickup' ) : __( 'No', 'alamin-vendor-tasks-dokan-clickup' ),
			'{toc_accepted}'        => $toc_enabled ? __( 'Yes', 'alamin-vendor-tasks-dokan-clickup' ) : __( 'No', 'alamin-vendor-tasks-dokan-clickup' ),
		);

		return str_replace( array_keys( $placeholders ), array_values( $placeholders ), $template );
	}

	/**
	 * Format vendor description as Markdown
	 *
	 * @since 1.4.0
	 *
	 * @param int    $vendor_id   Vendor user ID.
	 * @param string $full_name   Vendor full name.
	 * @param string $email       Vendor email.
	 * @param string $shop_name   Vendor shop name.
	 * @param string $shop_url    Vendor store URL.
	 * @param string $phone       Vendor phone.
	 * @param array  $address     Vendor address.
	 * @param array  $socials     Social profile URLs keyed by platform.
	 * @param bool   $is_trusted  Whether vendor is trusted.
	 * @param bool   $toc_enabled Whether vendor accepted T&C.
	 * @return string Formatted Markdown description.
	 */
	private function format_markdown_description( int $vendor_id, string $full_name, string $email, string $shop_name, string $shop_url, string $phone, array $address, array $socials = array(), bool $is_trusted = false, bool $toc_enabled = false ): string {
		$vendor = function_exists( 'dokan' ) ? dokan()->vendor->get( $vendor_id ) : null;

		$description_parts = array(
			'## Vendor Registration Details',
			'',
			'- **Name**: ' . sanitize_text_field( $full_name ),
			'- **Email**: ' . sanitize_email( $email ),
		);

		if ( $shop_name ) {
			$description_parts[] = '- **Shop Name**: ' . sanitize_text_field( $shop_name );
		}

		if ( $shop_url ) {
			$store_url           = esc_url( $shop_url );
			$description_parts[] = "- **Store URL**: [$store_url]($store_url)";
		}

		if ( $phone ) {
			$description_parts[] = '- **Phone**: ' . sanitize_text_field( $phone );
		}

		$location_parts = $this->get_address( $address );
		if ( ! empty( $location_parts ) ) {
			$description_parts[] = '- **Location**: ' . implode( ', ', $location_parts );
		}

		$description_parts[] = '- **Registered**: ' . ( $vendor instanceof Vendor ? esc_html( $vendor->get_register_date() ?? '' ) : '' );
		$description_parts[] = '- **User ID**: ' . absint( $vendor_id );
		$description_parts[] = '- **Trusted**: ' . ( $is_trusted ? __( 'Yes', 'alamin-vendor-tasks-dokan-clickup' ) : __( 'No', 'alamin-vendor-tasks-dokan-clickup' ) );
		$description_parts[] = '- **T&C Accepted**: ' . ( $toc_enabled ? __( 'Yes', 'alamin-vendor-tasks-dokan-clickup' ) : __( 'No', 'alamin-vendor-tasks-dokan-clickup' ) );

		if ( $vendor instanceof Vendor ) {
			$profile_url         = esc_url( $vendor->get_profile_url() );
			$description_parts[] = "- **Admin Profile**: [$profile_url]($profile_url)";
		}

		$social_parts = $this->format_social_profiles( $socials );
		if ( ! empty( $social_parts ) ) {
			$description_parts[] = '';
			$description_parts[] = '## Social Profiles';
			$description_parts[] = '';
			foreach ( $social_parts as $line ) {
				$description_parts[] = '- ' . $line;
			}
		}

		$description_parts[] = '';

		return implode( "\n", $description_parts );
	}

	/**
	 * Format vendor description as normal text
	 *
	 * @since 1.4.0
	 *
	 * @param int    $vendor_id   Vendor user ID.
	 * @param string $full_name   Vendor full name.
	 * @param string $email       Vendor email.
	 * @param string $shop_name   Vendor shop name.
	 * @param string $shop_url    Vendor store URL.
	 * @param string $phone       Vendor phone.
	 * @param array  $address     Vendor address.
	 * @param array  $socials     Social profile URLs keyed by platform.
	 * @param bool   $is_trusted  Whether vendor is trusted.
	 * @param bool   $toc_enabled Whether vendor accepted T&C.
	 * @return string Formatted normal text description.
	 */
	private function format_normal_description( int $vendor_id, string $full_name, string $email, string $shop_name, string $shop_url, string $phone, array $address, array $socials = array(), bool $is_trusted = false, bool $toc_enabled = false ): string {
		$vendor = function_exists( 'dokan' ) ? dokan()->vendor->get( $vendor_id ) : null;

		$description_parts = array(
			'Vendor Registration Details',
			'',
			'Name: ' . sanitize_text_field( $full_name ),
			'Email: ' . sanitize_email( $email ),
		);

		if ( $shop_name ) {
			$description_parts[] = 'Shop Name: ' . sanitize_text_field( $shop_name );
		}

		if ( $shop_url ) {
			$description_parts[] = 'Store URL: ' . esc_url( $shop_url );
		}

		if ( $phone ) {
			$description_parts[] = 'Phone: ' . sanitize_text_field( $phone );
		}

		$location_parts = $this->get_address( $address );
		if ( ! empty( $location_parts ) ) {
			$description_parts[] = 'Location: ' . implode( ', ', $location_parts );
		}

		$description_parts[] = 'Registered: ' . ( $vendor instanceof Vendor ? esc_html( $vendor->get_register_date() ?? '' ) : '' );
		$description_parts[] = 'User ID: ' . absint( $vendor_id );
		$description_parts[] = 'Trusted: ' . ( $is_trusted ? __( 'Yes', 'alamin-vendor-tasks-dokan-clickup' ) : __( 'No', 'alamin-vendor-tasks-dokan-clickup' ) );
		$description_parts[] = 'T&C Accepted: ' . ( $toc_enabled ? __( 'Yes', 'alamin-vendor-tasks-dokan-clickup' ) : __( 'No', 'alamin-vendor-tasks-dokan-clickup' ) );

		if ( $vendor instanceof Vendor ) {
			$description_parts[] = 'Admin Profile: ' . esc_url( $vendor->get_profile_url() );
		}

		$social_parts = $this->format_social_profiles( $socials );
		if ( ! empty( $social_parts ) ) {
			$description_parts[] = '';
			$description_parts[] = 'Social Profiles:';
			foreach ( $social_parts as $line ) {
				$description_parts[] = '  ' . $line;
			}
		}

		$description_parts[] = '';

		return implode( "\n", $description_parts );
	}

	/**
	 * Build non-empty social profile lines from the Dokan social array.
	 *
	 * Keys: fb, twitter, linkedin, youtube, tiktok, instagram, threads.
	 *
	 * @since 1.5.0
	 *
	 * @param array $socials Raw social profiles from Vendor::get_social_profiles().
	 * @return string[] Label: URL lines for each set profile.
	 */
	private function format_social_profiles( array $socials ): array {
		$labels = array(
			'fb'        => 'Facebook',
			'twitter'   => 'Twitter / X',
			'linkedin'  => 'LinkedIn',
			'youtube'   => 'YouTube',
			'tiktok'    => 'TikTok',
			'instagram' => 'Instagram',
			'threads'   => 'Threads',
		);

		$lines = array();
		foreach ( $labels as $key => $label ) {
			$url = trim( (string) ( $socials[ $key ] ?? '' ) );
			if ( $url ) {
				$lines[] = $label . ': ' . esc_url( $url );
			}
		}

		return $lines;
	}

	/**
	 * Format address parts into a single array of non-empty components
	 *
	 * @since 1.4.0
	 *
	 * @param array $address Address array with keys: street_1, street_2, city, state, zip, country.
	 * @return array
	 */
	private function get_address( array $address ): array {
		$location_parts = array();
		if ( ! empty( $address['street_1'] ) ) {
			$location_parts[] = sanitize_text_field( $address['street_1'] );
		}
		if ( ! empty( $address['street_2'] ) ) {
			$location_parts[] = sanitize_text_field( $address['street_2'] );
		}
		if ( ! empty( $address['city'] ) ) {
			$location_parts[] = sanitize_text_field( $address['city'] );
		}
		if ( ! empty( $address['zip'] ) ) {
			$location_parts[] = sanitize_text_field( $address['zip'] );
		}
		if ( ! empty( $address['state'] ) ) {
			$location_parts[] = sanitize_text_field( $address['state'] );
		}
		if ( ! empty( $address['country'] ) ) {
			$location_parts[] = sanitize_text_field( $address['country'] );
		}

		return $location_parts;
	}
}
