import 'package:dartboard_resume/models/dartboard_misc.dart';
import 'package:dartboard_resume/models/date_range.dart';
import 'package:dartboard_resume/models/document_text.dart';
import 'package:dartboard_resume/models/experience.dart';
import 'package:dartboard_resume/models/theme.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart';
import 'package:toml/toml.dart';

class DartboardData {
  DartboardData({
    required this.fullName,
    required this.phoneNumber,
    required this.email,
    // required this.address,
    required this.imagePath,
    required this.dartboardTheme,
    required this.experiences,
    required this.miscList,
  });

  factory DartboardData.fromToml(String tomlFilePath) {
    final tomlData = TomlDocument.loadSync(tomlFilePath).toMap();

    final List<Experience> exps = tomlData.entries
        .where((e) => Experience.filter(e.value))
        .map((MapEntry<String, dynamic> expsEntry) {
          final String subsection =
              tomlData['${expsEntry.key}_name'] as String? ?? _getSubsectionFromKey(expsEntry.key);
          final exps = (expsEntry.value as List).map((e) => e as Map<String, dynamic>).toList();
          return exps.map((exp) {
            final TomlLocalDate? start = exp['start'] as TomlLocalDate?;
            final TomlLocalDate? end = exp['end'] as TomlLocalDate?;
            return Experience(
              title: exp['title'] as String,
              subsection: subsection,
              range: DateRange(
                start: start == null ? null : DateTime(start.date.year, start.date.month),
                end: end == null ? null : DateTime(end.date.year, end.date.month),
              ),
              attributes: (exp['attributes'] as List)
                  .where((e) => e is String && e.isNotEmpty)
                  .map((e) => DocumentText(content: e as String))
                  .toList(),
              location: exp['location'] as String?,
            );
          }).toList();
        })
        .expand((i) => i)
        .toList();
    final List<DartboardMisc> misc =
        tomlData.entries.where((e) => DartboardMisc.filter(e.value)).map((MapEntry<String, dynamic> listEntry) {
      final String subsection = tomlData['${listEntry.key}_name'] as String? ?? _getSubsectionFromKey(listEntry.key);
      return DartboardMisc(
        subsection: subsection,
        attributes: (listEntry.value as List)
            .map((e) => (e as Map<String, dynamic>)['attributes'] as List)
            .expand((i) => i)
            .where((e) => e is String && e.isNotEmpty)
            .map((e) => DocumentText(content: e as String))
            .toList(),
      );
    }).toList();
    return DartboardData(
      fullName: tomlData['full_name'] as String,
      phoneNumber: tomlData['phone_number'] as String?,
      email: tomlData['email'] as String?,
      imagePath: tomlData['image'] as String?,
      dartboardTheme: DocumentTheme.fromToml(tomlData),
      experiences: exps,
      miscList: misc,
    );
  }

  final String fullName;
  final String? phoneNumber;
  final String? email;
  final String? imagePath;
  final DocumentTheme dartboardTheme;
  final List<Experience> experiences;
  final List<DartboardMisc> miscList;

  Font get font => dartboardTheme.font;

  PdfColor get primaryColor => dartboardTheme.primaryColor;
  PdfColor get accentColor => dartboardTheme.accentColor;
  PdfColor get backgroundColor => dartboardTheme.backgroundColor;

  TextStyle get headerTextStyle =>
      TextStyle(fontSize: 18, font: font, fontWeight: FontWeight.bold, color: const PdfColorGrey(0.18));
  TextStyle get subheaderTextStyle => TextStyle(fontSize: 14, font: font, color: const PdfColorGrey(0.3));
  TextStyle get defaultTextStyle => TextStyle(fontSize: 10, font: font, color: const PdfColorGrey(0.45));

  Map<String, List<Experience>> get groupedExperiences {
    final Map<String, List<Experience>> exps = {};
    for (final Experience exp in experiences) {
      if (!exps.containsKey(exp.subsection)) {
        exps[exp.subsection] = <Experience>[];
      }
      exps[exp.subsection]!.add(exp);
    }
    return exps;
  }

  Map<String, List<DartboardMisc>> get groupedMisc {
    final Map<String, List<DartboardMisc>> miscs = {};
    for (final DartboardMisc misc in miscList) {
      if (!miscs.containsKey(misc.subsection)) {
        miscs[misc.subsection] = <DartboardMisc>[];
      }
      miscs[misc.subsection]!.add(misc);
    }
    return miscs;
  }

  @override
  int get hashCode {
    return Object.hashAll([fullName, phoneNumber, email, imagePath, dartboardTheme, ...experiences, ...miscList]);
  }

  @override
  bool operator ==(Object other) {
    return super.hashCode == other.hashCode;
  }
}

String _getSubsectionFromKey(String key) {
  switch (key) {
    case 'exp':
      return 'Experience';
    case 'misc':
      return 'Miscelaneous';
    case 'edu':
      return 'Education';
    case '':
    default:
      return '';
  }
}