<?php

namespace ModernFields\CLI\Commands;

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

use WP_CLI_Command;
use WP_CLI;

defined('ABSPATH') || exit;

/**
 * Manages Modern Fields data via the command line.
 *
 * @since 1.0.0
 */
class ModernFieldsCommand extends WP_CLI_Command
{
  public function __construct(
    protected ExportService $exportService,
    protected ImportService $importService,
  ) {}

  /**
   * Exports field groups, CPTs, taxonomies and blocks to a JSON file.
   *
   * ## OPTIONS
   *
   * [--file=<file>]
   * : Path to the output file. Defaults to modern-fields-export-<timestamp>.json.
   *
   * [--groups=<ids>]
   * : Comma-separated IDs of field groups to export. Defaults to all.
   *
   * [--post-types=<ids>]
   * : Comma-separated IDs of CPT definitions to export. Defaults to all.
   *
   * [--taxonomies=<ids>]
   * : Comma-separated IDs of taxonomy definitions to export. Defaults to all.
   *
   * [--blocks=<ids>]
   * : Comma-separated IDs of block definitions to export. Defaults to all.
   *
   * [--stdout]
   * : Print JSON to stdout instead of writing a file.
   *
   * ## EXAMPLES
   *
   *   wp modern-fields export
   *   wp modern-fields export --file=backup.json
   *   wp modern-fields export --groups=12,34 --post-types=56
   *   wp modern-fields export --stdout | jq .
   *
   * @since 1.0.0
   */
  public function export(array $args, array $assoc_args): void
  {
    $group_ids     = $this->parseIds($assoc_args['groups'] ?? '');
    $post_type_ids = $this->parseIds($assoc_args['post-types'] ?? '');
    $taxonomy_ids  = $this->parseIds($assoc_args['taxonomies'] ?? '');
    $block_ids     = $this->parseIds($assoc_args['blocks'] ?? '');

    if (empty($group_ids)) {
      $group_ids = $this->getAllIds(MODERN_FIELDS_CPT_SLUG);
    }

    if (empty($post_type_ids)) {
      $post_type_ids = $this->getAllIds(MODERN_FIELDS_POST_TYPES_CPT_SLUG);
    }

    if (empty($taxonomy_ids)) {
      $taxonomy_ids = $this->getAllIds(MODERN_FIELDS_TAXONOMIES_CPT_SLUG);
    }

    if (empty($block_ids)) {
      $block_ids = $this->getAllIds(MODERN_FIELDS_BLOCKS_CPT_SLUG);
    }

    $data = $this->exportService->export($group_ids, $post_type_ids, $taxonomy_ids, $block_ids);
    $json = wp_json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

    if (WP_CLI\Utils\get_flag_value($assoc_args, 'stdout', false)) {
      echo $json . "\n";
      return;
    }

    $file = $assoc_args['file'] ?? sprintf('modern-fields-export-%s.json', gmdate('Y-m-d-His'));

    if (file_put_contents($file, $json) === false) {
      WP_CLI::error(sprintf('Could not write to file: %s', $file));
    }

    WP_CLI::success(sprintf(
      'Exported %d group(s), %d post type(s), %d taxonomy/taxonomies, %d block(s) → %s',
      count($data['groups']),
      count($data['post_types']),
      count($data['taxonomies']),
      count($data['blocks']),
      $file
    ));
  }

  /**
   * Imports field groups, CPTs, taxonomies and blocks from a JSON file.
   *
   * ## OPTIONS
   *
   * <file>
   * : Path to the JSON file to import.
   *
   * [--force]
   * : Overwrite items even when there are modification conflicts.
   *
   * [--dry-run]
   * : Preview what would be imported without writing to the database.
   *
   * ## EXAMPLES
   *
   *   wp modern-fields import export.json
   *   wp modern-fields import export.json --force
   *   wp modern-fields import export.json --dry-run
   *
   * @since 1.0.0
   */
  public function import(array $args, array $assoc_args): void
  {
    $file = $args[0] ?? '';

    if (empty($file) || !file_exists($file)) {
      WP_CLI::error(sprintf('File not found: %s', $file));
    }

    $json = file_get_contents($file);
    $data = json_decode($json, true);

    if (json_last_error() !== JSON_ERROR_NONE || !isset($data['mf_version'])) {
      WP_CLI::error('Invalid or malformed Modern Fields export file.');
    }

    $is_dry_run = WP_CLI\Utils\get_flag_value($assoc_args, 'dry-run', false);
    $force      = WP_CLI\Utils\get_flag_value($assoc_args, 'force', false);

    if ($is_dry_run) {
      $this->printDryRunSummary($data);
      return;
    }

    $force_uuids = $force ? $this->collectAllUuids($data) : [];
    $report      = $this->importService->import($data, $force_uuids);

    $this->printImportReport($report);
  }

  /**
   * @since 1.0.0
   */
  protected function printDryRunSummary(array $data): void
  {
    WP_CLI::line('--- Dry run — nothing will be written ---');

    $items = [];

    foreach ($data['groups'] ?? [] as $g) {
      $items[] = ['type' => 'group', 'title' => $g['title'] ?? '?', 'uuid' => $g['uuid'] ?? '?'];
    }

    foreach ($data['post_types'] ?? [] as $pt) {
      $items[] = ['type' => 'post_type', 'title' => $pt['title'] ?? '?', 'uuid' => $pt['uuid'] ?? '?'];
    }

    foreach ($data['taxonomies'] ?? [] as $t) {
      $items[] = ['type' => 'taxonomy', 'title' => $t['title'] ?? '?', 'uuid' => $t['uuid'] ?? '?'];
    }

    foreach ($data['blocks'] ?? [] as $b) {
      $items[] = ['type' => 'block', 'title' => $b['title'] ?? '?', 'uuid' => $b['uuid'] ?? '?'];
    }

    if (empty($items)) {
      WP_CLI::warning('The file contains no items to import.');
      return;
    }

    WP_CLI\Utils\format_items('table', $items, ['type', 'title', 'uuid']);
    WP_CLI::line(sprintf('Total: %d item(s).', count($items)));
  }

  /**
   * @since 1.0.0
   */
  protected function printImportReport(array $report): void
  {
    foreach ($report['created'] as $item) {
      WP_CLI::success(sprintf('[created] %s "%s" (ID: %d)', $item['type'], $item['title'], $item['id']));
    }

    foreach ($report['updated'] as $item) {
      WP_CLI::success(sprintf('[updated] %s "%s" (ID: %d)', $item['type'], $item['title'], $item['id']));
    }

    foreach ($report['conflicts'] as $item) {
      WP_CLI::warning(sprintf(
        '[conflict] %s "%s" — local modified %s is newer than export date %s. Use --force to override.',
        $item['type'],
        $item['title'],
        $item['local_modified'],
        $item['export_date']
      ));
    }

    foreach ($report['errors'] as $item) {
      WP_CLI::error(sprintf('[error] %s "%s": %s', $item['type'], $item['title'] ?? '?', $item['reason']), false);
    }

    $total     = count($report['created']) + count($report['updated']);
    $conflicts = count($report['conflicts']);
    $errors    = count($report['errors']);

    if ($errors > 0) {
      WP_CLI::warning(sprintf('Done with errors — %d imported, %d conflict(s), %d error(s).', $total, $conflicts, $errors));
    } elseif ($conflicts > 0) {
      WP_CLI::warning(sprintf('Done — %d imported, %d conflict(s) skipped. Use --force to override.', $total, $conflicts));
    } else {
      WP_CLI::success(sprintf('Done — %d item(s) imported.', $total));
    }
  }

  /**
   * @since 1.0.0
   * @param string $csv Comma-separated integer IDs.
   * @return int[]
   */
  protected function parseIds(string $csv): array
  {
    if (empty(trim($csv))) {
      return [];
    }

    return array_values(array_filter(array_map('absint', explode(',', $csv))));
  }

  /**
   * @since 1.0.0
   * @return int[]
   */
  protected function getAllIds(string $post_type): array
  {
    return get_posts([
      'post_type'      => $post_type,
      'post_status'    => 'any',
      'posts_per_page' => -1,
      'fields'         => 'ids',
    ]);
  }

  /**
   * Collects all UUIDs from the export payload (used with --force).
   *
   * @since 1.0.0
   * @return string[]
   */
  protected function collectAllUuids(array $data): array
  {
    $uuids = [];

    foreach (array_merge($data['groups'] ?? [], $data['post_types'] ?? [], $data['taxonomies'] ?? [], $data['blocks'] ?? []) as $item) {
      if (!empty($item['uuid'])) {
        $uuids[] = $item['uuid'];
      }
    }

    return $uuids;
  }
}
