import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:package_info_plus/package_info_plus.dart';
import 'package:xml/xml.dart';

class UpdateService {
  static const String _releasesRssUrl = 'https://git.hudsonriggs.systems/LambdaBankingConglomerate/rmtPocketWatcher/releases.rss';
  
  /// Check if the app was installed via MSIX (Windows Store-style installation)
  static bool isInstalledViaMsix() {
    if (!Platform.isWindows) return false;
    
    try {
      // MSIX apps are installed in WindowsApps folder
      final exePath = Platform.resolvedExecutable;
      return exePath.contains('WindowsApps') || 
             exePath.contains('Program Files\\WindowsApps');
    } catch (e) {
      return false;
    }
  }
  
  /// Check if an update is available by comparing current version with latest release
  Future<UpdateInfo?> checkForUpdates() async {
    try {
      // Get current app version
      final packageInfo = await PackageInfo.fromPlatform();
      final currentVersion = packageInfo.version;
      
      if (kDebugMode) {
        print('Current app version: $currentVersion');
        print('Checking for updates at: $_releasesRssUrl');
      }
      
      // Fetch latest release from Gitea RSS feed
      final response = await http.get(
        Uri.parse(_releasesRssUrl),
        headers: {
          'Accept': 'application/rss+xml, application/xml, text/xml',
          'User-Agent': 'rmtPocketWatcher/$currentVersion',
        },
      );
      
      if (response.statusCode == 200) {
        final document = XmlDocument.parse(response.body);
        final items = document.findAllElements('item');
        
        if (items.isEmpty) {
          if (kDebugMode) {
            print('No releases found in RSS feed');
          }
          return null;
        }
        
        // Get the latest release (first item in RSS feed)
        final latestItem = items.first;
        final title = latestItem.findElements('title').first.innerText;
        final link = latestItem.findElements('link').first.innerText;
        final description = latestItem.findElements('description').firstOrNull?.innerText ?? '';
        final pubDate = latestItem.findElements('pubDate').first.innerText;
        
        // Extract version from title (assuming format like "v1.2.3" or "Release v1.2.3")
        final versionMatch = RegExp(r'v?(\d+\.\d+\.\d+)').firstMatch(title);
        if (versionMatch == null) {
          if (kDebugMode) {
            print('Could not extract version from title: $title');
          }
          return null;
        }
        
        final latestVersion = versionMatch.group(1)!;
        
        if (kDebugMode) {
          print('Latest release version: $latestVersion');
          print('Release title: $title');
        }
        
        // Compare versions
        if (isNewerVersion(latestVersion, currentVersion)) {
          return UpdateInfo(
            currentVersion: currentVersion,
            latestVersion: latestVersion,
            releaseUrl: link,
            releaseName: title,
            releaseNotes: description,
            publishedAt: _parseRssDate(pubDate),
            assets: _generateAssetUrls(latestVersion), // Generate expected asset URLs
          );
        } else {
          if (kDebugMode) {
            print('App is up to date');
          }
          return null;
        }
      } else {
        if (kDebugMode) {
          print('Failed to fetch RSS feed: ${response.statusCode}');
          print('Response: ${response.body}');
        }
        return null;
      }
    } catch (e) {
      if (kDebugMode) {
        print('Error checking for updates: $e');
      }
      return null;
    }
  }
  
  /// Extract version number from git tag (e.g., "v1.2.3" -> "1.2.3")
  @visibleForTesting
  String extractVersionFromTag(String tag) {
    return tag.startsWith('v') ? tag.substring(1) : tag;
  }
  
  /// Compare two version strings (e.g., "1.2.3" vs "1.2.2")
  @visibleForTesting
  bool isNewerVersion(String latest, String current) {
    final latestParts = latest.split('.').map(int.parse).toList();
    final currentParts = current.split('.').map(int.parse).toList();
    
    // Ensure both have same number of parts
    while (latestParts.length < currentParts.length) {
      latestParts.add(0);
    }
    while (currentParts.length < latestParts.length) {
      currentParts.add(0);
    }
    
    for (int i = 0; i < latestParts.length; i++) {
      if (latestParts[i] > currentParts[i]) {
        return true;
      } else if (latestParts[i] < currentParts[i]) {
        return false;
      }
    }
    
    return false; // Versions are equal
  }
  
  /// Parse RSS date format to DateTime
  DateTime _parseRssDate(String rssDate) {
    try {
      // RSS dates are typically in RFC 2822 format
      // Example: "Mon, 02 Jan 2006 15:04:05 MST"
      return DateTime.parse(rssDate);
    } catch (e) {
      if (kDebugMode) {
        print('Failed to parse RSS date: $rssDate, error: $e');
      }
      return DateTime.now();
    }
  }
  
  /// Generate expected asset URLs based on version and platform
  List<ReleaseAsset> _generateAssetUrls(String version) {
    final baseUrl = 'https://git.hudsonriggs.systems/LambdaBankingConglomerate/rmtPocketWatcher/releases/download/v$version';
    
    return [
      // Windows Full Package (ZIP with all DLLs)
      ReleaseAsset(
        name: 'rmtPocketWatcher-Windows-v$version.zip',
        downloadUrl: '$baseUrl/rmtPocketWatcher-Windows-v$version.zip',
        size: 0,
        contentType: 'application/zip',
      ),
      // Windows Portable (self-extracting EXE)
      ReleaseAsset(
        name: 'rmtPocketWatcher-Windows-Portable-v$version.exe',
        downloadUrl: '$baseUrl/rmtPocketWatcher-Windows-Portable-v$version.exe',
        size: 0,
        contentType: 'application/octet-stream',
      ),
      // Windows MSIX Installer
      ReleaseAsset(
        name: 'rmtPocketWatcher-Windows-v$version.msix',
        downloadUrl: '$baseUrl/rmtPocketWatcher-Windows-v$version.msix',
        size: 0,
        contentType: 'application/msix',
      ),
      // Certificate for code signing verification
      ReleaseAsset(
        name: 'rmtPocketWatcher-Certificate.cer',
        downloadUrl: '$baseUrl/rmtPocketWatcher-Certificate.cer',
        size: 0,
        contentType: 'application/x-x509-ca-cert',
      ),
      // Android APK
      ReleaseAsset(
        name: 'rmtPocketWatcher-Android-v$version.apk',
        downloadUrl: '$baseUrl/rmtPocketWatcher-Android-v$version.apk',
        size: 0,
        contentType: 'application/vnd.android.package-archive',
      ),
    ];
  }
}

class UpdateInfo {
  final String currentVersion;
  final String latestVersion;
  final String releaseUrl;
  final String releaseName;
  final String releaseNotes;
  final DateTime publishedAt;
  final List<ReleaseAsset> assets;
  
  UpdateInfo({
    required this.currentVersion,
    required this.latestVersion,
    required this.releaseUrl,
    required this.releaseName,
    required this.releaseNotes,
    required this.publishedAt,
    required this.assets,
  });
  
  /// Get the appropriate download asset for the current platform
  ReleaseAsset? getAssetForCurrentPlatform() {
    if (kIsWeb) return null;
    
    switch (defaultTargetPlatform) {
      case TargetPlatform.windows:
        // If installed via MSIX, prefer MSIX for updates
        if (UpdateService.isInstalledViaMsix()) {
          var msix = assets.where((asset) => asset.name.endsWith('.msix')).firstOrNull;
          if (msix != null) return msix;
        }
        
        // Prefer portable self-extracting exe for non-MSIX installs
        var portable = assets.where((asset) => asset.name.contains('Portable') && asset.name.endsWith('.exe')).firstOrNull;
        if (portable != null) return portable;
        
        // Fall back to full Windows package (ZIP)
        var windows = assets.where((asset) => asset.name.contains('Windows') && asset.name.endsWith('.zip')).firstOrNull;
        if (windows != null) return windows;
        
        // Last resort: MSIX installer
        return assets.where((asset) => asset.name.endsWith('.msix')).firstOrNull;
        
      case TargetPlatform.macOS:
        return assets.where((asset) => 
          RegExp(r'macOS|macos|mac|darwin|\.dmg$|\.pkg$', caseSensitive: false).hasMatch(asset.name)
        ).firstOrNull;
        
      case TargetPlatform.linux:
        return assets.where((asset) => 
          RegExp(r'Linux|linux|\.deb$|\.rpm$|\.appimage$', caseSensitive: false).hasMatch(asset.name)
        ).firstOrNull;
        
      case TargetPlatform.android:
        return assets.where((asset) => asset.name.endsWith('.apk')).firstOrNull;
        
      case TargetPlatform.iOS:
        return assets.where((asset) => asset.name.endsWith('.ipa')).firstOrNull;
        
      default:
        return null;
    }
  }
}

class ReleaseAsset {
  final String name;
  final String downloadUrl;
  final int size;
  final String contentType;
  
  ReleaseAsset({
    required this.name,
    required this.downloadUrl,
    required this.size,
    required this.contentType,
  });
  
  String get formattedSize {
    if (size < 1024) return '${size}B';
    if (size < 1024 * 1024) return '${(size / 1024).toStringAsFixed(1)}KB';
    if (size < 1024 * 1024 * 1024) return '${(size / (1024 * 1024)).toStringAsFixed(1)}MB';
    return '${(size / (1024 * 1024 * 1024)).toStringAsFixed(1)}GB';
  }
}