import 'dart:io';
import 'package:path_provider/path_provider.dart';
import '../models/track.dart';
import 'track_database.dart';

/// GPX 1.1 fájl generáló.
/// A GPX az összes standard alkalmazással kompatibilis (OsmAnd, Komoot,
/// QGIS, gpsvisualizer.com stb.).
class GpxExporter {
  final TrackDatabase _db;
  GpxExporter([TrackDatabase? db]) : _db = db ?? TrackDatabase.instance;

  /// Elkészíti a GPX fájlt és visszaadja az elérési utat.
  Future<String> export(Track track) async {
    final points = await _db.getPoints(track.id!);
    final xml = _buildGpx(track, points);

    final dir = await getExternalStorageDirectory() ??
        await getApplicationDocumentsDirectory();
    final safeName =
        track.name.replaceAll(RegExp(r'[^a-zA-Z0-9_\-]'), '_').toLowerCase();
    final file = File('${dir.path}/${safeName}_${track.id}.gpx');
    await file.writeAsString(xml, encoding: utf8_encoding);
    return file.path;
  }

  String _buildGpx(Track track, List<TrackPoint> points) {
    final buf = StringBuffer();
    buf.writeln('<?xml version="1.0" encoding="UTF-8"?>');
    buf.writeln('<gpx version="1.1" creator="Terepi Segéd"');
    buf.writeln('     xmlns="http://www.topografix.com/GPX/1/1"');
    buf.writeln('     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"');
    buf.writeln('     xsi:schemaLocation="http://www.topografix.com/GPX/1/1 '
        'http://www.topografix.com/GPX/1/1/gpx.xsd">');

    buf.writeln('  <metadata>');
    buf.writeln('    <name>${_esc(track.name)}</name>');
    buf.writeln(
        '    <time>${track.startTime.toUtc().toIso8601String()}</time>');
    buf.writeln('  </metadata>');

    buf.writeln('  <trk>');
    buf.writeln('    <name>${_esc(track.name)}</name>');
    buf.writeln('    <desc>Forrás: ${_esc(track.source)}, '
        '${track.pointCount} pont, '
        '${track.distanceFormatted}</desc>');
    buf.writeln('    <trkseg>');

    for (final pt in points) {
      buf.write('      <trkpt lat="${pt.latitude}" lon="${pt.longitude}">');
      if (pt.altitude != null) {
        buf.write('<ele>${pt.altitude!.toStringAsFixed(3)}</ele>');
      }
      buf.write('<time>${pt.timestamp.toUtc().toIso8601String()}</time>');
      if (pt.speed != null) {
        buf.write('<speed>${pt.speed!.toStringAsFixed(2)}</speed>');
      }
      if (pt.heading != null) {
        buf.write('<course>${pt.heading!.toStringAsFixed(1)}</course>');
      }
      if (pt.accuracy != null) {
        buf.write('<hdop>${pt.accuracy!.toStringAsFixed(2)}</hdop>');
      }
      buf.writeln('</trkpt>');
    }

    buf.writeln('    </trkseg>');
    buf.writeln('  </trk>');
    buf.writeln('</gpx>');
    return buf.toString();
  }

  String _esc(String s) => s
      .replaceAll('&', '&amp;')
      .replaceAll('<', '&lt;')
      .replaceAll('>', '&gt;')
      .replaceAll('"', '&quot;');
}

// ignore: non_constant_identifier_names
final utf8_encoding = const SystemEncoding();
