<?php

namespace SoftminalB2B\Messaging;

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

use SoftminalB2B\Models\Conversation;
use SoftminalB2B\Models\Message;

/**
 * Shapes conversations and messages for the REST layer, so the admin inbox and
 * the storefront centre present the exact same data ([[project-messaging-feature]]).
 *
 * $side is the viewer's perspective ('shop' or 'buyer') and only decides which
 * read cursor drives the `unread` flag — never what data is exposed; ownership
 * is enforced by the controllers before anything reaches here.
 */
class Presenter
{
    /**
     * One inbox row. $unreadCount is the number of unread messages for $side
     * (the controller batches these); pass null to derive the boolean only.
     *
     * @return array<string, mixed>
     */
    public static function summary(Conversation $conversation, string $side, ?int $unreadCount = null): array
    {
        return [
            'id'          => (int) $conversation->id,
            'subject'     => self::subject($conversation),
            'status'      => (string) $conversation->status,
            'buyer'       => self::buyerName((int) $conversation->buyer_id),
            'anchor'      => self::anchor($conversation),
            'last_at'     => $conversation->last_message_at,
            'last_by'     => (string) $conversation->last_author_type,
            'unread'      => $unreadCount !== null
                ? $unreadCount > 0
                : $conversation->isUnreadFor($side),
            'unread_count' => (int) ($unreadCount ?? 0),
        ];
    }

    /**
     * A full thread: the conversation header plus every message in order.
     *
     * @return array<string, mixed>
     */
    public static function thread(Conversation $conversation, string $side): array
    {
        $messages = Message::where('conversation_id', (int) $conversation->id)
            ->orderBy('id', 'ASC')
            ->get();

        $lines = [];

        foreach ($messages as $message) {
            $lines[] = self::message($message);
        }

        return [
            'id'         => (int) $conversation->id,
            'subject'    => self::subject($conversation),
            'status'     => (string) $conversation->status,
            'buyer'      => self::buyerName((int) $conversation->buyer_id),
            'buyer_id'   => (int) $conversation->buyer_id,
            'anchor'     => self::anchor($conversation),
            'created_at' => $conversation->created_at,
            'messages'   => $lines,
            /**
             * Whether this thread can be turned into a quote (Pro, phase D).
             * Free never adds the filter, so the Inbox button stays hidden.
             *
             * @param bool         $can          Default false.
             * @param Conversation $conversation The thread.
             */
            'can_convert' => (bool) apply_filters('smb2b_conversation_can_convert', false, $conversation),
            // A quote-anchored thread is the quote's history — not deletable from
            // the inbox (delete the quote instead). Everything else can go.
            'deletable' => trim((string) $conversation->anchor_type) !== 'quote',
        ];
    }

    /**
     * @return array<string, mixed>
     */
    public static function message(Message $message): array
    {
        return [
            'id'          => (int) $message->id,
            'author_type' => (string) $message->author_type,
            'author'      => self::authorName($message),
            'body'        => (string) $message->body,
            'created_at'  => $message->created_at,
        ];
    }

    private static function subject(Conversation $conversation): string
    {
        $subject = trim((string) $conversation->subject);

        return $subject !== ''
            ? $subject
            : __('General enquiry', 'softminal-b2b-wholesale-for-woocommerce');
    }

    private static function authorName(Message $message): string
    {
        $type = (string) $message->author_type;

        if ($type === Message::AUTHOR_SHOP) {
            return __('Store', 'softminal-b2b-wholesale-for-woocommerce');
        }

        if ($type === Message::AUTHOR_SYSTEM) {
            return '';
        }

        return self::buyerName((int) $message->user_id);
    }

    private static function buyerName(int $userId): string
    {
        $user = $userId ? get_userdata($userId) : null;

        return $user
            ? $user->display_name
            : __('Customer', 'softminal-b2b-wholesale-for-woocommerce');
    }

    /**
     * A lightweight anchor descriptor. The rich context card (resolved buyer
     * price, order summary) is a Pro concern; core carries only the reference so
     * Pro can enrich it via the `smb2b_conversation_anchor` filter.
     *
     * @return array<string, mixed>|null
     */
    private static function anchor(Conversation $conversation): ?array
    {
        $type = trim((string) $conversation->anchor_type);
        $id   = (int) $conversation->anchor_id;

        if ($type === '' || $id <= 0) {
            return null;
        }

        $base = [
            'type'  => $type,
            'id'    => $id,
            'label' => self::anchorLabel($type, $id),
        ];

        /**
         * Enrich an anchor with a richer card (Pro). Filters may add a
         * `card` payload; core renders only `label` when absent.
         *
         * @param array<string, mixed> $base         The core anchor descriptor.
         * @param Conversation          $conversation The owning conversation.
         */
        return apply_filters('smb2b_conversation_anchor', $base, $conversation);
    }

    private static function anchorLabel(string $type, int $id): string
    {
        if ($type === 'product') {
            $product = function_exists('wc_get_product') ? wc_get_product($id) : null;

            return $product
                ? $product->get_name()
                /* translators: %d: product id */
                : sprintf(__('Product #%d', 'softminal-b2b-wholesale-for-woocommerce'), $id);
        }

        if ($type === 'order') {
            /* translators: %d: order number */
            return sprintf(__('Order #%d', 'softminal-b2b-wholesale-for-woocommerce'), $id);
        }

        if ($type === 'quote') {
            /* translators: %d: quote number */
            return sprintf(__('Quote #%d', 'softminal-b2b-wholesale-for-woocommerce'), $id);
        }

        return '';
    }
}
