import 'package:flutter/material.dart';
import 'package:latlong2/latlong.dart';

class AppUser {
  const AppUser({
    required this.id,
    required this.telegramId,
    required this.username,
    required this.firstName,
    required this.lastName,
    required this.photoUrl,
    required this.languageCode,
    required this.isAdmin,
  });

  factory AppUser.fromJson(Map<String, dynamic> json) {
    return AppUser(
      id: json['id'] as String,
      telegramId: json['telegramId'] as String,
      username: json['username'] as String?,
      firstName: json['firstName'] as String?,
      lastName: json['lastName'] as String?,
      photoUrl: json['photoUrl'] as String?,
      languageCode: json['languageCode'] as String?,
      isAdmin: json['isAdmin'] as bool? ?? false,
    );
  }

  final String id;
  final String telegramId;
  final String? username;
  final String? firstName;
  final String? lastName;
  final String? photoUrl;
  final String? languageCode;
  final bool isAdmin;
}

class VoiceExperienceDebug {
  const VoiceExperienceDebug({
    required this.id,
    required this.placeName,
    required this.userName,
    required this.status,
    required this.durationSeconds,
    required this.transcript,
    required this.analysis,
    required this.createdAt,
  });

  factory VoiceExperienceDebug.fromJson(Map<String, dynamic> json) {
    final place = json['place'] as Map<String, dynamic>;
    final user = json['user'] as Map<String, dynamic>?;
    final firstName = user?['firstName'] as String?;
    final username = user?['username'] as String?;
    final telegramId = user?['telegramId'] as String?;
    return VoiceExperienceDebug(
      id: json['id'] as String,
      placeName: place['name'] as String,
      userName: firstName?.trim().isNotEmpty == true
          ? firstName!
          : username?.trim().isNotEmpty == true
          ? '@$username'
          : telegramId ?? '',
      status: json['status'] as String,
      durationSeconds: json['durationSeconds'] as int,
      transcript: json['transcript'] as String?,
      analysis: json['analysis'] as Map<String, dynamic>?,
      createdAt: DateTime.parse(json['createdAt'] as String),
    );
  }

  final String id;
  final String placeName;
  final String userName;
  final String status;
  final int durationSeconds;
  final String? transcript;
  final Map<String, dynamic>? analysis;
  final DateTime createdAt;
}

enum PlaceTrait {
  calm,
  dynamic,
  intimate,
  open,
  solo,
  group,
  reset,
  impress,
  transit,
  clean,
  expressive,
}

extension PlaceTraitText on PlaceTrait {
  String get label {
    return switch (this) {
      PlaceTrait.calm => 'спокойное',
      PlaceTrait.dynamic => 'живое',
      PlaceTrait.intimate => 'камерное',
      PlaceTrait.open => 'открытое',
      PlaceTrait.solo => 'для себя',
      PlaceTrait.group => 'для компании',
      PlaceTrait.reset => 'выдохнуть',
      PlaceTrait.impress => 'впечатлить',
      PlaceTrait.transit => 'транзитное',
      PlaceTrait.clean => 'чистое',
      PlaceTrait.expressive => 'выразительное',
    };
  }

  IconData get icon {
    return switch (this) {
      PlaceTrait.calm => Icons.air_outlined,
      PlaceTrait.dynamic => Icons.bolt_outlined,
      PlaceTrait.intimate => Icons.lock_outline,
      PlaceTrait.open => Icons.public_outlined,
      PlaceTrait.solo => Icons.person_outline,
      PlaceTrait.group => Icons.forum_outlined,
      PlaceTrait.reset => Icons.spa_outlined,
      PlaceTrait.impress => Icons.diamond_outlined,
      PlaceTrait.transit => Icons.near_me_outlined,
      PlaceTrait.clean => Icons.wb_sunny_outlined,
      PlaceTrait.expressive => Icons.auto_awesome_outlined,
    };
  }
}

class PlaceRecommendation {
  const PlaceRecommendation({
    required this.id,
    required this.googlePlaceId,
    required this.name,
    required this.area,
    required this.photoUrls,
    required this.coordinate,
    required this.traits,
    required this.googlePrimaryType,
    required this.googleTypes,
    required this.googleBusinessStatus,
    required this.googleRating,
    required this.googleUserRatingCount,
    required this.googleRegularOpeningHours,
    required this.googleCurrentOpeningHours,
    required this.isFavorite,
  });

  final String id;
  final String googlePlaceId;
  final String name;
  final String area;
  final List<String> photoUrls;
  final LatLng coordinate;
  final Set<PlaceTrait> traits;
  final String? googlePrimaryType;
  final List<String> googleTypes;
  final String? googleBusinessStatus;
  final double? googleRating;
  final int? googleUserRatingCount;
  final Map<String, dynamic>? googleRegularOpeningHours;
  final Map<String, dynamic>? googleCurrentOpeningHours;
  final bool isFavorite;

  String? get coverPhotoUrl => photoUrls.isEmpty ? null : photoUrls.first;

  PlaceRecommendation copyWith({bool? isFavorite}) {
    return PlaceRecommendation(
      id: id,
      googlePlaceId: googlePlaceId,
      name: name,
      area: area,
      photoUrls: photoUrls,
      coordinate: coordinate,
      traits: traits,
      googlePrimaryType: googlePrimaryType,
      googleTypes: googleTypes,
      googleBusinessStatus: googleBusinessStatus,
      googleRating: googleRating,
      googleUserRatingCount: googleUserRatingCount,
      googleRegularOpeningHours: googleRegularOpeningHours,
      googleCurrentOpeningHours: googleCurrentOpeningHours,
      isFavorite: isFavorite ?? this.isFavorite,
    );
  }
}

class VoicePlaceRecommendationResult {
  const VoicePlaceRecommendationResult({
    required this.transcript,
    required this.tags,
    required this.summary,
    required this.places,
  });

  final String transcript;
  final List<String> tags;
  final String summary;
  final List<PlaceRecommendation> places;
}

class VoiceReviewDraft {
  const VoiceReviewDraft({
    required this.placeName,
    required this.duration,
    required this.extractedTraits,
    required this.evidence,
  });

  final String placeName;
  final Duration duration;
  final Set<PlaceTrait> extractedTraits;
  final List<String> evidence;

  bool get isLongEnough => duration.inSeconds >= 30;

  VoiceReviewDraft copyWith({
    String? placeName,
    Duration? duration,
    Set<PlaceTrait>? extractedTraits,
    List<String>? evidence,
  }) {
    return VoiceReviewDraft(
      placeName: placeName ?? this.placeName,
      duration: duration ?? this.duration,
      extractedTraits: extractedTraits ?? this.extractedTraits,
      evidence: evidence ?? this.evidence,
    );
  }
}

class TelegramBotLogin {
  const TelegramBotLogin({
    required this.token,
    required this.botUrl,
    required this.expiresAt,
  });

  factory TelegramBotLogin.fromJson(Map<String, dynamic> json) {
    return TelegramBotLogin(
      token: json['token'] as String,
      botUrl: json['botUrl'] as String,
      expiresAt: DateTime.parse(json['expiresAt'] as String),
    );
  }

  final String token;
  final String botUrl;
  final DateTime expiresAt;
}

class TelegramBotLoginSession {
  const TelegramBotLoginSession({
    required this.sessionToken,
    required this.user,
  });

  factory TelegramBotLoginSession.fromJson(Map<String, dynamic> json) {
    return TelegramBotLoginSession(
      sessionToken: json['sessionToken'] as String,
      user: AppUser.fromJson(json['user'] as Map<String, dynamic>),
    );
  }

  final String sessionToken;
  final AppUser user;
}
