import 'package:equatable/equatable.dart';

import '../../../domain/entities/wall_config.dart';

/// State for a single viewer
class ViewerState extends Equatable {
  final int viewerId;
  final int currentCameraId;
  final bool isLive;
  final bool hasAlarm;
  final bool isLocked;
  final String? lockedBy;

  const ViewerState({
    required this.viewerId,
    this.currentCameraId = 0,
    this.isLive = true,
    this.hasAlarm = false,
    this.isLocked = false,
    this.lockedBy,
  });

  bool get hasCamera => currentCameraId > 0;
  bool get isLockedByOther => isLocked && lockedBy != null;

  ViewerState copyWith({
    int? currentCameraId,
    bool? isLive,
    bool? hasAlarm,
    bool? isLocked,
    String? lockedBy,
  }) {
    return ViewerState(
      viewerId: viewerId,
      currentCameraId: currentCameraId ?? this.currentCameraId,
      isLive: isLive ?? this.isLive,
      hasAlarm: hasAlarm ?? this.hasAlarm,
      isLocked: isLocked ?? this.isLocked,
      lockedBy: lockedBy ?? this.lockedBy,
    );
  }

  @override
  List<Object?> get props =>
      [viewerId, currentCameraId, isLive, hasAlarm, isLocked, lockedBy];
}

/// Main wall bloc state
class WallState extends Equatable {
  final WallConfig? config;
  final bool isLoading;
  final String? error;

  // Selection state
  final int? selectedViewerId;
  final int? selectedPhysicalMonitorId;

  // Camera input state
  final int cameraPrefix; // 500, 501, 502
  final String cameraNumberInput; // Up to 6 digits typed by user
  final bool isEditing; // Whether camera input is active

  // Viewer states (keyed by viewer ID)
  final Map<int, ViewerState> viewerStates;

  // Expanded sections
  final Set<String> expandedSections;

  const WallState({
    this.config,
    this.isLoading = false,
    this.error,
    this.selectedViewerId,
    this.selectedPhysicalMonitorId,
    this.cameraPrefix = 500,
    this.cameraNumberInput = '',
    this.isEditing = false,
    this.viewerStates = const {},
    this.expandedSections = const {},
  });

  static const int _maxLength = 6;
  static const List<int> _prefixes = [500, 501, 502];

  /// Compose camera number with prefix (legacy CameraNumber.GetCameraNumberWithPrefix).
  /// If digits > prefix length: use digits as-is, right-pad with zeros.
  /// If digits <= prefix length: prefix + left-padded digits.
  int? get fullCameraNumber {
    if (cameraNumberInput.isEmpty) return null;

    final prefix = cameraPrefix.toString();
    final String composed;

    if (cameraNumberInput.length > prefix.length) {
      composed = cameraNumberInput.padRight(_maxLength, '0');
    } else {
      composed = prefix +
          cameraNumberInput.padLeft(_maxLength - prefix.length, '0');
    }

    return int.tryParse(composed);
  }

  /// Display string: typed digits only (no prefix shown in field).
  String get cameraInputDisplay {
    if (!isEditing || cameraNumberInput.isEmpty) return '';
    return cameraNumberInput;
  }

  /// Check if a viewer is selected
  bool isViewerSelected(int viewerId) => selectedViewerId == viewerId;

  /// Check if a physical monitor is selected (any of its viewers)
  bool isPhysicalMonitorSelected(PhysicalMonitor monitor) =>
      selectedPhysicalMonitorId == monitor.id;

  /// Get viewer state
  ViewerState getViewerState(int viewerId) {
    return viewerStates[viewerId] ?? ViewerState(viewerId: viewerId);
  }

  /// Check if section is expanded
  bool isSectionExpanded(String sectionId) =>
      expandedSections.contains(sectionId);

  /// Check if CrossSwitch can be executed
  bool get canExecuteCrossSwitch {
    if (selectedViewerId == null) return false;
    if (!isEditing || cameraNumberInput.isEmpty) return false;
    if (fullCameraNumber == null) return false;
    final viewerState = getViewerState(selectedViewerId!);
    if (viewerState.hasAlarm) return false;
    return true;
  }

  WallState copyWith({
    WallConfig? config,
    bool? isLoading,
    String? error,
    int? selectedViewerId,
    int? selectedPhysicalMonitorId,
    int? cameraPrefix,
    String? cameraNumberInput,
    bool? isEditing,
    Map<int, ViewerState>? viewerStates,
    Set<String>? expandedSections,
    bool clearSelection = false,
    bool clearError = false,
  }) {
    return WallState(
      config: config ?? this.config,
      isLoading: isLoading ?? this.isLoading,
      error: clearError ? null : (error ?? this.error),
      selectedViewerId:
          clearSelection ? null : (selectedViewerId ?? this.selectedViewerId),
      selectedPhysicalMonitorId: clearSelection
          ? null
          : (selectedPhysicalMonitorId ?? this.selectedPhysicalMonitorId),
      cameraPrefix: cameraPrefix ?? this.cameraPrefix,
      cameraNumberInput: cameraNumberInput ?? this.cameraNumberInput,
      isEditing: isEditing ?? this.isEditing,
      viewerStates: viewerStates ?? this.viewerStates,
      expandedSections: expandedSections ?? this.expandedSections,
    );
  }

  @override
  List<Object?> get props => [
        config,
        isLoading,
        error,
        selectedViewerId,
        selectedPhysicalMonitorId,
        cameraPrefix,
        cameraNumberInput,
        isEditing,
        viewerStates,
        expandedSections,
      ];
}
