import 'dart:convert';

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

import '../enums/note_type.dart';

class NoteItem {
  final int? id;
  final int? projectId;
  final NoteType type;
  final List<LatLng> points; // ← szerkesztéshez mindig elérhető
  final Color color;
  final double opacity;
  final double strokeWidth;
  final Color strokeColor;
  final String label;
  final DateTime createdAt;

  const NoteItem(
      {this.id,
      this.projectId,
      required this.type,
      required this.points,
      required this.color,
      this.opacity = 0.5,
      this.strokeWidth = 3.0,
      required this.strokeColor,
      this.label = '',
      required this.createdAt});

  NoteItem copyWith({
    List<LatLng>? points,
    Color? color,
    double? opacity,
    double? strokeWidth,
    Color? strokeColor,
    String? label,
  }) =>
      NoteItem(
        id: id,
        projectId: projectId,
        type: type,
        points: points ?? this.points,
        color: color ?? this.color,
        opacity: opacity ?? this.opacity,
        strokeWidth: strokeWidth ?? this.strokeWidth,
        strokeColor: strokeColor ?? this.strokeColor,
        label: label ?? this.label,
        createdAt: createdAt,
      );
  // ── Koordináta ↔ GeoJSON ────────────────────────────────────────

  static List<LatLng> _parsePoints(String json) {
    final geom = jsonDecode(json) as Map<String, dynamic>;
    final gType = geom['type'] as String;
    final coords = geom['coordinates'];

    switch (gType) {
      case 'Point':
        final c = coords as List;
        return [
          LatLng(
            (c[1] as num).toDouble(),
            (c[0] as num).toDouble(),
          )
        ];

      case 'LineString':
        return (coords as List)
            .map((c) => LatLng(
                  (c[1] as num).toDouble(),
                  (c[0] as num).toDouble(),
                ))
            .toList();

      case 'Polygon':
        // Külső gyűrű (index 0)
        return ((coords as List)[0] as List)
            .map((c) => LatLng(
                  (c[1] as num).toDouble(),
                  (c[0] as num).toDouble(),
                ))
            .toList();

      default:
        return [];
    }
  }

  String _toPointsJson() {
    List<dynamic> coords;
    String gType;

    switch (type) {
      case NoteType.point:
        // GeoJSON: [lon, lat]
        gType = 'Point';
        coords = [points.first.longitude, points.first.latitude];

      case NoteType.line:
        gType = 'LineString';
        coords = points.map((p) => [p.longitude, p.latitude]).toList();

      case NoteType.polygon:
        gType = 'Polygon';
        final ring = points.map((p) => [p.longitude, p.latitude]).toList();
        // Polygon zárt: első = utolsó pont
        if (ring.isNotEmpty) {
          final first = ring.first;
          final last = ring.last;
          final isClosed = first[0] == last[0] && first[1] == last[1];

          if (!isClosed) ring.add(List.from(first));
        }
        coords = [ring];
    }

    return jsonEncode({'type': gType, 'coordinates': coords});
  }
  // ── SQLite ↔ Map ────────────────────────────────────────────────

  static Color _parseColor(String hex) {
    final h = hex.replaceFirst('#', '');
    return Color(int.parse(h.length == 6 ? 'FF$h' : h, radix: 16));
  }

  static String _colorHex(Color c) =>
      '#${c.value.toRadixString(16).padLeft(8, '0').substring(2).toUpperCase()}';

  Map<String, dynamic> toMap() => {
        if (id != null) 'id': id,
        if (projectId != null) 'project_id': projectId,
        'type': type.name,
        'points_json': _toPointsJson(),
        'color': _colorHex(color),
        'opacity': opacity,
        'stroke_width': strokeWidth,
        'stroke_color': _colorHex(strokeColor),
        'label': label,
        'created_at': createdAt.toIso8601String(),
      };

  factory NoteItem.fromMap(Map<String, dynamic> m) => NoteItem(
        id: m['id'] as int?,
        projectId: m['project_id'] as int?,
        type: NoteType.values.firstWhere((t) => t.name == (m['type'] as String),
            orElse: () => NoteType.point),
        points: _parsePoints(m['points_json'] as String),
        color: _parseColor(m['color'] as String? ?? '#185FA5'),
        opacity: (m['opacity'] as num?)?.toDouble() ?? 0.5,
        strokeWidth: (m['stroke_width'] as num?)?.toDouble() ?? 3.0,
        strokeColor: _parseColor(m['stroke_color'] as String? ?? '#FFD700'),
        label: m['label'] as String? ?? '',
        createdAt: DateTime.parse(m['created_at'] as String),
      );

  /// Kitöltési szín az opacity-val alkalmazva.
  Color get fillColor => Color.fromARGB(
        (opacity * 255).round(),
        color.red,
        color.green,
        color.blue,
      );

  // Rendereléshez — a hitValue hordozza az id-t a tap detektáláshoz
  Polyline<int> toPolyline() => Polyline(
        points: points,
        color: color,
        strokeWidth: strokeWidth,
        hitValue: id!,
      );

  Polygon<int> toPolygon() => Polygon(
      points: points,
      color: color.withOpacity(opacity),
      borderColor: strokeColor,
      borderStrokeWidth: strokeWidth,
      label: label.isEmpty ? null : label,
      hitValue: id!,
      labelStyle: TextStyle(fontSize: 10.0));
}
