<?php

namespace ModernFields\Sync\Services;

use ModernFields\ImportExport\Services\ExportService;
use ModernFields\ImportExport\Services\ImportService;

defined('ABSPATH') || exit;

/**
 * Reads and writes mf-json files in the active theme directory.
 *
 * When a `mf-json/` folder exists in the theme, each saved field group is
 * automatically persisted as `{uuid}.json` so developers can version-control
 * their field group definitions alongside their theme.
 *
 * @since 0.8
 */
class JsonSyncService
{
  public function __construct(
    protected ExportService $exportService,
    protected ImportService $importService,
  ) {}

  /**
   * Returns the absolute path to the theme's mf-json directory, or null if it
   * does not exist.
   *
   * @since 0.8
   */
  public function getThemeJsonDir(): ?string
  {
    $dir = get_stylesheet_directory() . '/mf-json';
    return is_dir($dir) ? $dir : null;
  }

  /**
   * Serializes a field group and writes it to the theme's mf-json directory.
   *
   * Silently skips if the directory does not exist or the group cannot be
   * serialized (e.g. it is in trash).
   *
   * @since 0.8
   * @param int $post_id
   * @return void
   */
  public function writeGroupJson(int $post_id): void
  {
    $dir = $this->getThemeJsonDir();
    if (!$dir) {
      return;
    }

    $data = $this->exportService->export([$post_id], [], []);

    if (empty($data['groups'])) {
      return;
    }

    $group = $data['groups'][0];
    $uuid  = $group['uuid'];

    file_put_contents(
      $dir . '/' . $uuid . '.json',
      wp_json_encode($group, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
    );
  }

  /**
   * Deletes the JSON file for a given UUID from the theme directory.
   *
   * @since 0.8
   * @param int $post_id
   * @return void
   */
  public function deleteGroupJson(int $post_id): void
  {
    $dir = $this->getThemeJsonDir();
    if (!$dir) {
      return;
    }

    $uuid = get_post_meta($post_id, 'mf_uuid', true);
    if (empty($uuid)) {
      return;
    }

    $file = $dir . '/' . $uuid . '.json';
    if (file_exists($file)) {
      unlink($file);
    }
  }

  /**
   * Returns the sync status for every JSON file found in the theme directory.
   *
   * Each entry contains:
   * - uuid         string        UUID of the group
   * - group_id     int|null      WP post ID if the group exists on this site
   * - json_modified string|null  ISO-8601 modified date stored in the JSON file
   * - has_update   bool          true when the JSON file is newer than the DB group
   *
   * @since 0.8
   * @return array
   */
  public function getAllSyncStatuses(): array
  {
    $dir = $this->getThemeJsonDir();
    if (!$dir) {
      return [];
    }

    $files    = glob($dir . '/*.json') ?: [];
    $statuses = [];

    foreach ($files as $file) {
      $raw = file_get_contents($file);
      if (!$raw) {
        continue;
      }

      $data = json_decode($raw, true);
      if (empty($data['uuid'])) {
        continue;
      }

      $uuid     = $data['uuid'];
      $group_id = $this->findGroupIdByUuid($uuid);

      $json_modified  = $data['modified'] ?? null;
      $has_update     = false;

      if ($group_id && $json_modified) {
        $group_modified = get_post_modified_time('U', true, $group_id);
        $has_update     = strtotime($json_modified) > (int) $group_modified;
      }

      $statuses[] = [
        'uuid'          => $uuid,
        'group_id'      => $group_id,
        'json_modified' => $json_modified,
        'has_update'    => $has_update,
      ];
    }

    return $statuses;
  }

  /**
   * Imports a field group from its JSON file in the theme directory.
   *
   * Conflict detection is bypassed because the user has explicitly requested
   * the sync.
   *
   * @since 0.8
   * @param string $uuid
   * @return array Import report from ImportService.
   */
  public function importFromJson(string $uuid): array
  {
    $dir = $this->getThemeJsonDir();
    if (!$dir) {
      return ['error' => 'no_theme_json_dir'];
    }

    $file = $dir . '/' . sanitize_file_name($uuid) . '.json';
    if (!file_exists($file)) {
      return ['error' => 'file_not_found'];
    }

    $group_data = json_decode(file_get_contents($file), true);
    if (empty($group_data['uuid'])) {
      return ['error' => 'invalid_json'];
    }

    $payload = [
      'mf_version'  => MODERN_FIELDS_VERSION,
      'exported_at' => $group_data['modified'] ?? null,
      'groups'      => [$group_data],
      'post_types'  => [],
      'taxonomies'  => [],
    ];

    # Force update — the user explicitly triggered the sync
    return $this->importService->import($payload, [$uuid]);
  }

  /**
   * @since 0.8
   */
  protected function findGroupIdByUuid(string $uuid): ?int
  {
    $posts = get_posts([
      'post_type'      => MODERN_FIELDS_CPT_SLUG,
      'post_status'    => 'any',
      'posts_per_page' => 1,
      'meta_key'       => 'mf_uuid',
      'meta_value'     => $uuid,
      'fields'         => 'ids',
    ]);

    return !empty($posts) ? (int) $posts[0] : null;
  }
}
