import 'dart:async';
import 'dart:convert';
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; // SystemSound
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;

enum EggSize { small, normal, large }
enum EggDoneness { soft, medium, hard }
enum EggOrigin { fridge, room }

void main() {
  runApp(const BoiledEggApp());
}

class BoiledEggApp extends StatelessWidget {
  const BoiledEggApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Eierkoch-Assistent',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.orange),
        useMaterial3: true,
      ),
      home: const EggTimerScreen(),
    );
  }
}

class EggTimerScreen extends StatefulWidget {
  const EggTimerScreen({super.key});

  @override
  State<EggTimerScreen> createState() => _EggTimerScreenState();
}

class _EggTimerScreenState extends State<EggTimerScreen> {
  EggSize _size = EggSize.normal;
  EggDoneness _doneness = EggDoneness.medium;
  EggOrigin _eggOrigin = EggOrigin.fridge;

  int? _altitude; // in Metern
  Duration _cookTime = const Duration(minutes: 7);
  Duration _remainingTime = Duration.zero;
  Timer? _timer;

  bool _loadingLocation = false;
  String? _error;

  @override
  void initState() {
    super.initState();
    _initLocationAndAltitude();
  }

  Future<void> _initLocationAndAltitude() async {
    setState(() {
      _loadingLocation = true;
      _error = null;
    });

    try {
      // Berechtigungen prüfen/anfordern
      LocationPermission permission = await Geolocator.checkPermission();
      if (permission == LocationPermission.denied) {
        permission = await Geolocator.requestPermission();
      }
      if (permission == LocationPermission.deniedForever ||
          permission == LocationPermission.denied) {
        setState(() {
          _error = 'Standortberechtigung verweigert';
          _loadingLocation = false;
        });
        return;
      }

      // Standort ermitteln
      final position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.high,
      );

      // Höhe über Webservice ermitteln
      final altitude =
      await _fetchAltitudeFromWeb(position.latitude, position.longitude);

      setState(() {
        _altitude = altitude;
        _loadingLocation = false;
      });

      _recalculateCookTime();
    } catch (e) {
      setState(() {
        _error = 'Fehler: $e';
        _loadingLocation = false;
      });
    }
  }

  Future<int> _fetchAltitudeFromWeb(double lat, double lon) async {
    final uri = Uri.parse(
      'https://api.open-elevation.com/api/v1/lookup?locations=$lat,$lon',
    );

    final response = await http.get(uri);
    if (response.statusCode == 200) {
      final data = jsonDecode(response.body) as Map<String, dynamic>;
      final results = data['results'] as List<dynamic>;
      if (results.isNotEmpty) {
        final elevation = results[0]['elevation'] as num;
        return elevation.round();
      } else {
        throw Exception('Keine Höhen-Daten erhalten');
      }
    } else {
      throw Exception('HTTP-Fehler: ${response.statusCode}');
    }
  }

  void _recalculateCookTime() {
    if (_altitude == null) return;
    final newTime = calculateCookTime(
      altitudeMeters: _altitude!,
      size: _size,
      doneness: _doneness,
      origin: _eggOrigin,
    );
    setState(() {
      _cookTime = newTime;
      if (_timer == null || !_timer!.isActive) {
        _remainingTime = newTime;
      }
    });
  }

  void _startTimer() {
    _timer?.cancel();
    setState(() {
      _remainingTime = _cookTime;
    });

    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (_remainingTime.inSeconds <= 1) {
        timer.cancel();
        setState(() {
          _remainingTime = Duration.zero;
        });
        _playAlarm();
        return;
      }
      setState(() {
        _remainingTime = _remainingTime - const Duration(seconds: 1);
      });
    });
  }

  void _stopTimer() {
    _timer?.cancel();
    setState(() {
      _remainingTime = _cookTime;
    });
  }

  Future<void> _playAlarm() async {
    await SystemSound.play(SystemSoundType.alert);
  }

  String _formatDuration(Duration d) {
    final m = d.inMinutes.remainder(60).toString().padLeft(2, '0');
    final s = d.inSeconds.remainder(60).toString().padLeft(2, '0');
    return '$m:$s';
  }

  double _progressValue() {
    if (_cookTime.inSeconds == 0) return 0.0;
    final total = _cookTime.inSeconds;
    final remaining = _remainingTime.inSeconds;
    final elapsed = (total - remaining).clamp(0, total);
    return elapsed / total; // 0.0 = Start, 1.0 = fertig
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final altitudeText =
    _altitude != null ? '$_altitude m über NN' : 'unbekannt';

    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'Eierkoch-Assistent',
          style: TextStyle(
            fontWeight: FontWeight.bold,
          ),
        ),
        centerTitle: true,
      ),
      body: Stack(
        children: [
          // Hintergrundgrafik (durchscheinendes Ei)
          Positioned.fill(
            child: Opacity(
              opacity: 0.15,
              child: Image.asset(
                'assets/egg_background.png',
                fit: BoxFit.cover,
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: _loadingLocation
                ? const Center(child: CircularProgressIndicator())
                : SingleChildScrollView(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  if (_error != null)
                    Text(
                      _error!,
                      style: const TextStyle(color: Colors.red),
                      textAlign: TextAlign.center,
                    ),
                  const SizedBox(height: 12),
                  Text(
                    'Meereshöhe: $altitudeText',
                    textAlign: TextAlign.center,
                  ),
                  const SizedBox(height: 16),

                  // Ausgangstemperatur
                  const Text(
                    'Ausgangstemperatur des Eis',
                    style: TextStyle(fontWeight: FontWeight.bold),
                    textAlign: TextAlign.center,
                  ),
                  const SizedBox(height: 8),
                  Wrap(
                    alignment: WrapAlignment.center,
                    spacing: 8,
                    children: [
                      ChoiceChip(
                        label: const Text('Kühlschrank'),
                        selected: _eggOrigin == EggOrigin.fridge,
                        onSelected: (_) {
                          setState(() => _eggOrigin = EggOrigin.fridge);
                          _recalculateCookTime();
                        },
                      ),
                      ChoiceChip(
                        label: const Text('Raumtemperatur'),
                        selected: _eggOrigin == EggOrigin.room,
                        onSelected: (_) {
                          setState(() => _eggOrigin = EggOrigin.room);
                          _recalculateCookTime();
                        },
                      ),
                    ],
                  ),
                  const SizedBox(height: 16),

                  // Eiergröße
                  const Text(
                    'Eiergröße',
                    style: TextStyle(fontWeight: FontWeight.bold),
                    textAlign: TextAlign.center,
                  ),
                  const SizedBox(height: 8),
                  Wrap(
                    alignment: WrapAlignment.center,
                    spacing: 8,
                    children: [
                      ChoiceChip(
                        label: const Text('klein'),
                        selected: _size == EggSize.small,
                        onSelected: (_) {
                          setState(() => _size = EggSize.small);
                          _recalculateCookTime();
                        },
                      ),
                      ChoiceChip(
                        label: const Text('normal'),
                        selected: _size == EggSize.normal,
                        onSelected: (_) {
                          setState(() => _size = EggSize.normal);
                          _recalculateCookTime();
                        },
                      ),
                      ChoiceChip(
                        label: const Text('groß'),
                        selected: _size == EggSize.large,
                        onSelected: (_) {
                          setState(() => _size = EggSize.large);
                          _recalculateCookTime();
                        },
                      ),
                    ],
                  ),
                  const SizedBox(height: 16),

                  // Kochgrad
                  const Text(
                    'Kochgrad',
                    style: TextStyle(fontWeight: FontWeight.bold),
                    textAlign: TextAlign.center,
                  ),
                  const SizedBox(height: 8),
                  Wrap(
                    alignment: WrapAlignment.center,
                    spacing: 8,
                    children: [
                      ChoiceChip(
                        label: const Text('weich'),
                        selected: _doneness == EggDoneness.soft,
                        onSelected: (_) {
                          setState(() => _doneness = EggDoneness.soft);
                          _recalculateCookTime();
                        },
                      ),
                      ChoiceChip(
                        label: const Text('mittel'),
                        selected: _doneness == EggDoneness.medium,
                        onSelected: (_) {
                          setState(() => _doneness = EggDoneness.medium);
                          _recalculateCookTime();
                        },
                      ),
                      ChoiceChip(
                        label: const Text('hart'),
                        selected: _doneness == EggDoneness.hard,
                        onSelected: (_) {
                          setState(() => _doneness = EggDoneness.hard);
                          _recalculateCookTime();
                        },
                      ),
                    ],
                  ),
                  const SizedBox(height: 24),

                  Text(
                    'Berechnete Kochzeit: ${_formatDuration(_cookTime)}',
                    textAlign: TextAlign.center,
                  ),
                  const SizedBox(height: 16),

                  // Ring-Anzeige der Restzeit
                  SizedBox(
                    width: 180,
                    height: 180,
                    child: Stack(
                      alignment: Alignment.center,
                      children: [
                        SizedBox(
                          width: 160,
                          height: 160,
                          child: CircularProgressIndicator(
                            value: _cookTime.inSeconds == 0
                                ? 0.0
                                : _progressValue(),
                            strokeWidth: 10,
                          ),
                        ),
                        Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            const Text(
                              'Restzeit',
                              style: TextStyle(fontSize: 14),
                            ),
                            Text(
                              _formatDuration(_remainingTime),
                              style: const TextStyle(
                                fontSize: 24,
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                          ],
                        ),
                      ],
                    ),
                  ),

                  const SizedBox(height: 24),

                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      // Start-Button: nur aktiv, wenn Höhe bekannt
                      // und Timer nicht läuft
                      ElevatedButton.icon(
                        onPressed: (_altitude == null)
                            ? null
                            : (_timer == null || !_timer!.isActive)
                            ? () => _startTimer()
                            : null,
                        icon: const Icon(Icons.timer),
                        label: const Text('Start'),
                      ),
                      const SizedBox(width: 16),
                      // Stop-Button: nur aktiv, wenn Timer läuft
                      ElevatedButton.icon(
                        onPressed: (_timer != null && _timer!.isActive)
                            ? () => _stopTimer()
                            : null,
                        icon: const Icon(Icons.stop),
                        label: const Text('Stop'),
                      ),
                    ],
                  ),
                  const SizedBox(height: 16),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: const [
                      Icon(
                        Icons.smart_toy,
                        size: 18,
                        color: Colors.black54,
                      ),
                      SizedBox(width: 6),
                      Text(
                        'Made with AI by ChatGPT',
                        style: TextStyle(color: Colors.black54),
                      ),
                    ],
                  ),
                  const SizedBox(height: 8),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// Siedetemperatur des Wassers aus Höhe (vereinfachtes Modell)
double boilingTemperatureFromAltitude(int altitudeMeters) {
  // ca. -1 °C pro 285 m über NN
  final drop = altitudeMeters / 285.0;
  final t = 100.0 - drop;

  // Sicherheitsbereich 80–100 °C
  final clamped = t.clamp(80.0, 100.0);
  return clamped.toDouble();
}

// Physikalisch basierte Kochzeitformel
Duration calculateCookTime({
  required int altitudeMeters,
  required EggSize size,
  required EggDoneness doneness,
  required EggOrigin origin,
}) {
  // 1. Masse des Eis in g
  double massGrams;
  switch (size) {
    case EggSize.small:
      massGrams = 47.0;
      break;
    case EggSize.normal:
      massGrams = 57.0; // mittleres Ei
      break;
    case EggSize.large:
      massGrams = 67.0;
      break;
  }

  // 2. Zieltemperatur des Eigelbs Ty (°C)
  double Ty;
  switch (doneness) {
    case EggDoneness.soft:
      Ty = 65.0;
      break;
    case EggDoneness.medium:
      Ty = 72.0;
      break;
    case EggDoneness.hard:
      Ty = 82.0;
      break;
  }

  // 3. Anfangstemperatur To (°C)
  final double To = switch (origin) {
    EggOrigin.fridge => 7.0,
    EggOrigin.room => 20.0,
  };

  // 4. Wassertemperatur Tw (Siedetemperatur) aus Höhe
  final double Tw = boilingTemperatureFromAltitude(altitudeMeters);

  // 5. Materialkonstanten
  const double rho = 1.038; // g/cm^3
  const double c = 3.7;     // J/(g*K)
  const double K = 5.4e-3;  // W/(cm*K)

  // 6. Vorfaktor
  final double factorNumerator =
      math.pow(massGrams, 2.0 / 3.0) * c * math.pow(rho, 1.0 / 3.0);
  final double factorDenominator =
      K * math.pi * math.pi * math.pow((4.0 * math.pi / 3.0), 2.0 / 3.0);
  final double factor = factorNumerator / factorDenominator;

  // 7. Logarithmus-Term
  final double insideLog = 0.76 * ((To - Tw) / (Ty - Tw));

  if (insideLog <= 0) {
    // Fallback, falls Parameter zu extrem sind
    return const Duration(minutes: 6);
  }

  final double tSeconds = factor * math.log(insideLog.abs());

  int seconds = tSeconds.round();

  if (!seconds.isFinite || seconds <= 0) {
    seconds = 300; // 5 Minuten Fallback
  }
  if (seconds > 1800) {
    seconds = 1800; // max. 30 Minuten
  }

  return Duration(seconds: seconds);
}
