import 'package:json_annotation/json_annotation.dart';

import '../../../api_response.dart';

part 'get_poll_state_response.g.dart';

/// Poll-`status`-Werte der Talk-API.
const int pollStatusOpen = 0;
const int pollStatusClosed = 1;

/// Poll-`resultMode`-Werte der Talk-API.
const int pollResultModePublic = 0;
const int pollResultModeHidden = 1;

/// `participantType`-Werte (aus dem Room), die eine Umfrage schließen dürfen:
/// Owner (1), Moderator (2) und Gast-Moderator (6).
const Set<int> pollModeratorParticipantTypes = {1, 2, 6};

@JsonSerializable(explicitToJson: true)
class GetPollStateResponse extends ApiResponse {
  GetPollStateResponseObject data;

  GetPollStateResponse(this.data);

  factory GetPollStateResponse.fromJson(Map<String, dynamic> json) =>
      _$GetPollStateResponseFromJson(json);
  Map<String, dynamic> toJson() => _$GetPollStateResponseToJson(this);
}

@JsonSerializable(explicitToJson: true)
class GetPollStateResponseObject {
  int id;
  String question;
  List<String> options;
  dynamic votes;
  String actorType;
  String actorId;
  String actorDisplayName;
  int status;
  int resultMode;
  int maxVotes;
  List<int> votedSelf;
  int? numVoters;
  List<dynamic>? details;

  GetPollStateResponseObject(
    this.id,
    this.question,
    this.options,
    this.votes,
    this.actorType,
    this.actorId,
    this.actorDisplayName,
    this.status,
    this.resultMode,
    this.maxVotes,
    this.votedSelf,
    this.numVoters,
    this.details,
  );

  factory GetPollStateResponseObject.fromJson(Map<String, dynamic> json) =>
      _$GetPollStateResponseObjectFromJson(json);
  Map<String, dynamic> toJson() => _$GetPollStateResponseObjectToJson(this);

  bool get isClosed => status == pollStatusClosed;

  bool get resultsHidden => resultMode == pollResultModeHidden;

  /// Ergebnisse sichtbar: öffentliche Umfragen jederzeit, verborgene erst nach
  /// dem Schließen. Der Typ von `votes` taugt nicht als Signal (siehe unten).
  bool get resultsVisible => resultMode == pollResultModePublic || isClosed;

  /// Normalisiert das dynamische `votes`-Feld zu einer Map: der Server liefert
  /// bei verborgenen Ergebnissen (und ohne Stimmen) eine leere Liste statt Map.
  Map<String, num> get voteCounts {
    final raw = votes;
    if (raw is! Map) return const {};
    final result = <String, num>{};
    raw.forEach((key, value) {
      if (key is String && value is num) result[key] = value;
    });
    return result;
  }

  /// Darf der Nutzer die (offene) Umfrage schließen: als Ersteller oder Moderator.
  bool canClose({required String selfId, required int participantType}) {
    if (isClosed) return false;
    final isCreator = actorType == 'users' && actorId == selfId;
    final isModerator = pollModeratorParticipantTypes.contains(participantType);
    return isCreator || isModerator;
  }
}
