import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';

import '../models/receivable_models.dart';
import '../models/shipment_models.dart';
import 'app_settings_repository.dart';
import 'calendar_sync_service.dart';

/// Maps domain entities (shipments, receivables, etc.) to Google Calendar events.
class BusinessCalendarMapper {
  BusinessCalendarMapper({
    CalendarSyncService? calendarSyncService,
    AppSettingsRepository? settingsRepository,
  })  : _calendarSyncService = calendarSyncService ?? CalendarSyncService(),
        _settingsRepository = settingsRepository ?? AppSettingsRepository();

  final CalendarSyncService _calendarSyncService;
  final AppSettingsRepository _settingsRepository;
  final NumberFormat _currencyFormat = NumberFormat.currency(locale: 'ja_JP', symbol: '¥');

  Future<bool> _ensureReady() async {
    final enabled = await _settingsRepository.getGoogleCalendarEnabled();
    if (!enabled) return false;
    final ready = await _calendarSyncService.ensureSignedIn();
    return ready;
  }

  Future<void> syncShipments(List<Shipment> shipments) async {
    if (shipments.isEmpty) return;
    if (!await _ensureReady()) return;
    for (final shipment in shipments) {
      await _syncShipment(shipment);
    }
  }

  Future<void> syncShipment(Shipment shipment) async {
    if (!await _ensureReady()) return;
    await _syncShipment(shipment);
  }

  Future<void> syncReceivables(List<ReceivableInvoiceSummary> summaries) async {
    if (summaries.isEmpty) return;
    if (!await _ensureReady()) return;
    for (final summary in summaries) {
      await _syncReceivable(summary);
    }
  }

  Future<void> syncReceivable(ReceivableInvoiceSummary summary) async {
    if (!await _ensureReady()) return;
    await _syncReceivable(summary);
  }

  Future<void> _syncShipment(Shipment shipment) async {
    final date = shipment.scheduledShipDate ?? shipment.actualShipDate;
    if (date == null) return;
    final start = DateTime(date.year, date.month, date.day, 9);
    final end = start.add(const Duration(hours: 2));
    final summary = '[出荷] ${(shipment.customerNameSnapshot ?? '取引先未設定')}';
    final buffer = StringBuffer()
      ..writeln('受注番号: ${shipment.orderNumberSnapshot ?? '-'}')
      ..writeln('ステータス: ${shipment.status.displayName}')
      ..writeln('配送業者: ${shipment.carrierName ?? '-'}')
      ..writeln('追跡番号: ${shipment.trackingNumber ?? '-'}');
    if (shipment.trackingUrl?.isNotEmpty == true) {
      buffer.writeln('トラッキングURL: ${shipment.trackingUrl}');
    }
    try {
      await _calendarSyncService.createOrUpdateEvent(
        eventId: 'shipment-${shipment.id}',
        summary: summary,
        description: buffer.toString(),
        start: start,
        end: end,
        extendedProperties: {
          'type': 'shipment',
          'shipmentId': shipment.id,
          if (shipment.orderNumberSnapshot != null) 'orderNumber': shipment.orderNumberSnapshot!,
          if (shipment.customerNameSnapshot != null) 'customer': shipment.customerNameSnapshot!,
        },
      );
    } catch (e, stack) {
      debugPrint('Failed to sync shipment ${shipment.id} to calendar: $e\n$stack');
    }
  }

  Future<void> _syncReceivable(ReceivableInvoiceSummary summary) async {
    final dueDate = summary.dueDate;
    final start = DateTime(dueDate.year, dueDate.month, dueDate.day, 10);
    final end = start.add(const Duration(hours: 1));
    final title = '[入金予定] ${summary.customerName}';
    final description = StringBuffer()
      ..writeln('請求書番号: ${summary.invoiceNumber}')
      ..writeln('請求日: ${DateFormat('yyyy/MM/dd').format(summary.invoiceDate)}')
      ..writeln('期日: ${DateFormat('yyyy/MM/dd').format(summary.dueDate)}')
      ..writeln('請求額: ${_currencyFormat.format(summary.totalAmount)}')
      ..writeln('入金済み: ${_currencyFormat.format(summary.paidAmount)}')
      ..writeln('残高: ${_currencyFormat.format(summary.outstandingAmount)}');
    try {
      await _calendarSyncService.createOrUpdateEvent(
        eventId: 'receivable-${summary.invoiceId}',
        summary: title,
        description: description.toString(),
        start: start,
        end: end,
        extendedProperties: {
          'type': 'receivable',
          'invoiceId': summary.invoiceId,
          'invoiceNumber': summary.invoiceNumber,
        },
      );
    } catch (e, stack) {
      debugPrint('Failed to sync receivable ${summary.invoiceId} to calendar: $e\n$stack');
    }
  }
}
