import 'dart:convert';

import 'package:http/http.dart' as http;

/// Lightweight HTTP client for the WooCommerce REST API v3.
///
/// Handles authentication (Basic Auth over HTTPS) and pagination.
/// Only read-only product listing is implemented for now.
class WooCommerceApiClient {
  /// Base URL of the WordPress site (e.g. `https://store.kellcreations.com`).
  final String siteUrl;

  /// WooCommerce REST API consumer key.
  final String consumerKey;

  /// WooCommerce REST API consumer secret.
  final String consumerSecret;

  /// Optional [http.Client] for testing / injection.
  final http.Client _httpClient;

  WooCommerceApiClient({
    required this.siteUrl,
    required this.consumerKey,
    required this.consumerSecret,
    http.Client? httpClient,
  }) : _httpClient = httpClient ?? http.Client();

  /// The base endpoint for WooCommerce REST API v3.
  String get _baseEndpoint => '$siteUrl/wp-json/wc/v3';

  /// Fetches a paginated list of products from WooCommerce.
  ///
  /// [page] is 1-based. [perPage] defaults to 100 (WooCommerce max).
  /// Returns the raw JSON list of product maps.
  Future<List<Map<String, dynamic>>> getProducts({int page = 1, int perPage = 100}) async {
    final uri = Uri.parse(
      '$_baseEndpoint/products',
    ).replace(queryParameters: {'page': page.toString(), 'per_page': perPage.toString()});

    final response = await _httpClient.get(uri, headers: _authHeaders);

    if (response.statusCode != 200) {
      throw WooCommerceApiException(
        statusCode: response.statusCode,
        message: 'Failed to fetch products: ${response.reasonPhrase}',
        body: response.body,
      );
    }

    final decoded = jsonDecode(response.body);
    if (decoded is! List) {
      throw WooCommerceApiException(
        statusCode: response.statusCode,
        message: 'Unexpected response format: expected a JSON array',
        body: response.body,
      );
    }

    return decoded.cast<Map<String, dynamic>>();
  }

  /// Fetches all products by paginating through the WooCommerce API.
  ///
  /// Keeps requesting pages until a page returns fewer items than [perPage].
  Future<List<Map<String, dynamic>>> getAllProducts({int perPage = 100}) async {
    final allProducts = <Map<String, dynamic>>[];
    var page = 1;

    while (true) {
      final batch = await getProducts(page: page, perPage: perPage);
      allProducts.addAll(batch);

      if (batch.length < perPage) break;
      page++;
    }

    return allProducts;
  }

  /// Basic Auth headers for WooCommerce REST API.
  Map<String, String> get _authHeaders {
    final credentials = base64Encode(utf8.encode('$consumerKey:$consumerSecret'));
    return {'Authorization': 'Basic $credentials', 'Content-Type': 'application/json'};
  }

  /// Sends a partial update (PUT) to a single WooCommerce product.
  ///
  /// Only the fields present in [body] are changed on the remote product.
  /// Returns the full product JSON that WooCommerce echoes back.
  Future<Map<String, dynamic>> updateProduct(String productId, Map<String, dynamic> body) async {
    final uri = Uri.parse('$_baseEndpoint/products/$productId');

    final response = await _httpClient.put(uri, headers: _authHeaders, body: jsonEncode(body));

    if (response.statusCode != 200) {
      throw WooCommerceApiException(
        statusCode: response.statusCode,
        message: 'Failed to update product $productId: ${response.reasonPhrase}',
        body: response.body,
      );
    }

    final decoded = jsonDecode(response.body);
    if (decoded is! Map<String, dynamic>) {
      throw WooCommerceApiException(
        statusCode: response.statusCode,
        message: 'Unexpected response format: expected a JSON object',
        body: response.body,
      );
    }

    return decoded;
  }

  /// Releases the underlying HTTP client resources.
  void dispose() {
    _httpClient.close();
  }
}

/// Exception thrown when the WooCommerce API returns an error.
class WooCommerceApiException implements Exception {
  final int statusCode;
  final String message;
  final String body;

  const WooCommerceApiException({
    required this.statusCode,
    required this.message,
    required this.body,
  });

  @override
  String toString() => 'WooCommerceApiException($statusCode): $message';
}
