<?php

namespace FleekDash\Controllers\Post;

use FleekDash\API\Posts\PostsDataFormatter;

/**
 * Post formatting utilities
 *
 * Handles formatting post data for different response formats
 * (detail view, grid view, etc.) and image data processing.
 *
 * @package FleekDash\Controllers\Post
 * @since 2.2.0
 */
class PostFormatter
{
    /**
     * Format post data for detail view
     *
     * @param \WP_Post $post
     * @return array Formatted post data
     */
    public static function formatPost(\WP_Post $post): array
    {
        $author = \get_userdata($post->post_author);
        $avatar = get_avatar_url($post->post_author);
        $featured_media = self::buildFeaturedMediaForDetail($post);
        $formatted_meta = self::buildFormattedMetaForDetail($post->ID);
        $terms = self::buildTaxonomiesForDetail($post);
        $formatted_categories = self::buildCategoriesListForDetail($post->ID);

        return [
            'id' => $post->ID,
            'post_type' => $post->post_type,
            'title' => [
                'raw' => $post->post_title,
                'rendered' => get_the_title($post->ID)
            ],
            'content' => [
                'raw' => $post->post_content,
                'rendered' => \apply_filters('the_content', $post->post_content)
            ],
            'excerpt' => [
                'raw' => $post->post_excerpt,
                'rendered' => get_the_excerpt($post)
            ],
            'author' => [
                'id' => $post->post_author,
                'name' => $author ? $author->display_name : '',
                'avatar' => $avatar,
                'username' => $author ? $author->user_login : '',
            ],
            'featured_media' => $featured_media,
            'status' => $post->post_status,
            'date' => [
                'published' => get_the_date('c', $post->ID),
                'modified' => get_the_modified_date('c', $post->ID)
            ],
            'link' => get_permalink($post->ID),
            'meta' => [
                'comments_count' => (string) get_comments_number($post->ID),
                'categories' => $formatted_categories,
                'custom_fields' => $formatted_meta,
                'taxonomies' => $terms
            ]
        ];
    }

    /**
     * @return array{id: int, url: string|false}
     */
    private static function buildFeaturedMediaForDetail(\WP_Post $post): array
    {
        $featured_media = [
            'id' => 0,
            'url' => false
        ];

        if (!has_post_thumbnail($post->ID)) {
            return $featured_media;
        }

        $thumbnail_id = get_post_thumbnail_id($post->ID);
        $thumbnail = \wp_get_attachment_image_src($thumbnail_id, 'full');

        if ($thumbnail) {
            $featured_media = [
                'id' => $thumbnail_id,
                'url' => $thumbnail[0]
            ];
        }

        return $featured_media;
    }

    /**
     * @return array<string, mixed>
     */
    private static function buildFormattedMetaForDetail(int $post_id): array
    {
        $meta = \get_post_meta($post_id);
        $formatted_meta = [];

        if (empty($meta)) {
            return $formatted_meta;
        }

        foreach ($meta as $key => $values) {
            if (strpos($key, '_') === 0) {
                continue;
            }

            $formatted_meta[$key] = count($values) === 1 ? $values[0] : $values;
        }

        return $formatted_meta;
    }

    /**
     * @return array<string, array<int, array{id: int, name: string, slug: string}>>
     */
    private static function buildTaxonomiesForDetail(\WP_Post $post): array
    {
        $taxonomies = get_object_taxonomies($post->post_type);
        $terms = [];

        foreach ($taxonomies as $taxonomy) {
            $post_terms = wp_get_post_terms($post->ID, $taxonomy);

            if (empty($post_terms) || is_wp_error($post_terms)) {
                continue;
            }

            $formatted_terms = [];

            foreach ($post_terms as $term) {
                $formatted_terms[] = [
                    'id' => $term->term_id,
                    'name' => $term->name,
                    'slug' => $term->slug
                ];
            }

            $terms[$taxonomy] = $formatted_terms;
        }

        return $terms;
    }

    /**
     * @return array<int, array{id: int, name: string, slug: string}>
     */
    private static function buildCategoriesListForDetail(int $post_id): array
    {
        $categories = wp_get_post_categories($post_id, ['fields' => 'all']);
        $formatted_categories = [];

        foreach ($categories as $category) {
            $formatted_categories[] = [
                'id' => $category->term_id,
                'name' => $category->name,
                'slug' => $category->slug
            ];
        }

        return $formatted_categories;
    }

    /**
     * `post_date_gmt` is stored as UTC (`Y-m-d H:i:s`). Expose as RFC3339 so the grid can
     * compute relative time without mixing site-local wall time with the browser timezone.
     *
     * @param string $mysqlGmt Value from `$post->post_date_gmt`
     */
    public static function formatPostDateGmtAtom(string $mysqlGmt): string
    {
        $result = '';
        $trimmed = trim($mysqlGmt);
        $isValid = $trimmed !== '' && $trimmed !== '0000-00-00 00:00:00';
        if ($isValid) {
            $dt = \DateTimeImmutable::createFromFormat(
                'Y-m-d H:i:s',
                $trimmed,
                new \DateTimeZone('UTC'),
            );
            if ($dt !== false) {
                $result = $dt->format(\DateTimeInterface::ATOM);
            }
        }
        return $result;
    }

    /**
     * Format post data for grid view
     *
     * @param \WP_Post $post
     * @return array Formatted post data for grid
     */
    public static function formatPostForGrid(\WP_Post $post): array
    {
        $author_data = self::buildAuthorDataForGrid($post);
        $image_data = self::getPostImageData($post->ID);
        $thumb = $image_data['url'];
        $subtitle = self::buildSubtitleForGrid($post);
        $relative_date = PostsDataFormatter::getRelativeTime($post->post_date);

        $category_data = self::buildTermsGridPayload($post->ID, 'category');
        $labels_data = self::buildAllTaxonomyTermsGridPayload($post);
        $template = self::resolvePageTemplateForGrid($post);
        $parent_id = $post->post_parent > 0 ? (int) $post->post_parent : 0;

        return array(
            'id' => $post->ID,
            'thumb' => $thumb,
            'title' => $post->post_title,
            'subtitle' => $subtitle,
            'slug' => $post->post_name,
            'status' => $post->post_status,
            'content' => wp_trim_words($post->post_content, 30),
            'excerpt' => $post->post_excerpt,
            'author' => $author_data,
            'avatarUrl' => $author_data ? $author_data['avatarUrl'] : '',
            'date' => \mysql_to_rfc3339($post->post_date),
            'date_gmt' => self::formatPostDateGmtAtom((string) $post->post_date_gmt),
            'relative_date' => $relative_date,
            'category' => $category_data,
            'labels' => $labels_data,
            'created_date' => \mysql_to_rfc3339($post->post_date),
            'updated_date' => \mysql_to_rfc3339($post->post_modified),
            'post_type' => $post->post_type,
            'template' => $template,
            'parent' => $parent_id,
            'link' => self::resolveViewLinkForGrid($post),
        );
    }

    /**
     * Permalink or preview URL for grid/calendar "View" actions.
     *
     * @param \WP_Post $post
     */
    private static function resolveViewLinkForGrid(\WP_Post $post): string
    {
        $preview_statuses = ['draft', 'pending', 'future'];
        if (in_array($post->post_status, $preview_statuses, true)) {
            $preview = \get_preview_post_link($post);
            if (is_string($preview) && $preview !== '') {
                return $preview;
            }
        }

        $permalink = \get_permalink($post->ID);
        return is_string($permalink) ? $permalink : '';
    }

    /**
     * @return array{id: int, name: string, email: string, avatarUrl: string}|null
     */
    private static function buildAuthorDataForGrid(\WP_Post $post): ?array
    {
        $author = \get_userdata($post->post_author);

        if (!$author) {
            return null;
        }

        return array(
            'id' => $author->ID,
            'name' => $author->display_name,
            'email' => $author->user_email,
            'avatarUrl' => get_avatar_url($author->ID, array('size' => 32)),
        );
    }

    private static function buildSubtitleForGrid(\WP_Post $post): string
    {
        if (!empty($post->post_excerpt)) {
            return wp_trim_words($post->post_excerpt, 20);
        }

        if (!empty($post->post_content)) {
            return wp_trim_words($post->post_content, 20);
        }

        return '';
    }

    /**
     * @return array<int, array{id: string, name: string, slug: string}>
     */
    private static function buildTermsGridPayload(int $post_id, string $taxonomy): array
    {
        $terms = wp_get_post_terms($post_id, $taxonomy, array('fields' => 'all'));
        $items = array();

        if (is_wp_error($terms) || empty($terms)) {
            return $items;
        }

        foreach ($terms as $term) {
            $items[] = array(
                'id' => (string) $term->term_id,
                'name' => $term->name,
                'slug' => $term->slug,
            );
        }

        return $items;
    }

    /**
     * Non-hierarchical taxonomy terms for the grid labels column.
     * Hierarchical taxonomies (e.g. category) belong in dedicated grid columns.
     *
     * @return array<int, array{id: string, name: string, slug: string, taxonomy: string}>
     */
    private static function buildAllTaxonomyTermsGridPayload(\WP_Post $post): array
    {
        $items = array();
        $taxonomies = get_object_taxonomies($post->post_type, 'objects');

        foreach ($taxonomies as $taxonomy) {
            if (!PostFilterOptionsHelper::shouldIncludeTaxonomyInLabels($post->post_type, $taxonomy)) {
                continue;
            }

            $terms = wp_get_post_terms($post->ID, $taxonomy->name, array('fields' => 'all'));
            if (is_wp_error($terms) || empty($terms)) {
                continue;
            }

            foreach ($terms as $term) {
                $items[] = array(
                    'id' => (string) $term->term_id,
                    'name' => $term->name,
                    'slug' => $term->slug,
                    'taxonomy' => $taxonomy->name,
                );
            }
        }

        return $items;
    }

    private static function resolvePageTemplateForGrid(\WP_Post $post): string
    {
        if ($post->post_type !== 'page') {
            return '';
        }

        $template = \get_post_meta($post->ID, '_wp_page_template', true);

        if ($template === false || $template === '') {
            return '';
        }

        return $template;
    }

    /**
     * Get post image data with proper priority order
     *
     * @param int $post_id The post ID
     * @return array Array with 'url' and 'type' keys
     */
    public static function getPostImageData(int $post_id): array
    {
        $from_logo = self::tryLogoImageData($post_id);
        $from_featured = self::tryFeaturedImageData($post_id);
        $from_attached = self::tryAttachedImageData($post_id);
        $picked = $from_logo ?? $from_featured ?? $from_attached;

        if ($picked === null) {
            $picked = [
                'url' => '',
                'type' => 'none'
            ];
        }

        return $picked;
    }

    /**
     * @return array{url: string, type: string}|null
     */
    private static function tryLogoImageData(int $post_id): ?array
    {
        $logo_id = \get_post_meta($post_id, 'logo', true);
        $result = null;

        if ($logo_id) {
            $logo_url = self::getSmallestAvailableImageUrl($logo_id);
            if ($logo_url !== '') {
                $result = [
                    'url' => $logo_url,
                    'type' => 'logo'
                ];
            }
        }

        return $result;
    }

    /**
     * @return array{url: string, type: string}|null
     */
    private static function tryFeaturedImageData(int $post_id): ?array
    {
        $result = null;
        $has_thumb = has_post_thumbnail($post_id);
        $thumbnail_id = $has_thumb ? get_post_thumbnail_id($post_id) : 0;

        if ($has_thumb && $thumbnail_id) {
            $thumbnail_url = self::getSmallestAvailableImageUrl($thumbnail_id);
            if ($thumbnail_url !== '') {
                $result = [
                    'url' => $thumbnail_url,
                    'type' => 'featured'
                ];
            }
        }

        return $result;
    }

    /**
     * @return array{url: string, type: string}|null
     */
    private static function tryAttachedImageData(int $post_id): ?array
    {
        $result = null;
        $attached_images = get_attached_media('image', $post_id);
        $first_image = !empty($attached_images) ? reset($attached_images) : false;
        $attachment_id = ($first_image && isset($first_image->ID)) ? (int) $first_image->ID : 0;

        if ($attachment_id > 0) {
            $image_url = self::getSmallestAvailableImageUrl($attachment_id);
            if ($image_url !== '') {
                $result = [
                    'url' => $image_url,
                    'type' => 'attached'
                ];
            }
        }

        return $result;
    }

    /**
     * @param int $attachment_id
     * @return string[]
     */
    private static function collectAttachmentImageUrlCandidates(int $attachment_id): array
    {
        $sizes = array_merge(
            array('fleekdash-preview'),
            array('medium_large', 'large', 'medium', 'thumbnail'),
            array('fleekdash-thumbnail')
        );
        $candidates = array();

        foreach ($sizes as $size) {
            $candidates[] = wp_get_attachment_image_url($attachment_id, $size) ?: '';
        }

        $candidates[] = \wp_get_attachment_url($attachment_id) ?: '';

        return $candidates;
    }

    /**
     * @param string[] $candidates
     * @return string
     */
    private static function firstNonEmptyString(array $candidates)
    {
        foreach ($candidates as $candidate) {
            if ($candidate) {
                return $candidate;
            }
        }

        return '';
    }

    /**
     * @param int $attachment_id
     * @return string
     */
    private static function getSmallestAvailableImageUrl(int $attachment_id): string
    {
        if (!$attachment_id) {
            return '';
        }

        return self::firstNonEmptyString(
            self::collectAttachmentImageUrlCandidates($attachment_id)
        );
    }
}
