import 'dart:async';

import 'package:dio/dio.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';

class FilePdf extends StatefulWidget {
  final String pdf;
  final String? searchTerm;
  final String title;

  const FilePdf({
    super.key,
    required this.pdf,
    required this.title,
    this.searchTerm,
  });

  @override
  // ignore: library_private_types_in_public_api
  _FilePdfState createState() => _FilePdfState();
}

class _FilePdfState extends State<FilePdf> {
  late Future<String> _pdfPathFuture;
  late PdfViewerController _pdfViewerController;
  late PdfTextSearchResult _pdfTextSearchResult;
  final _baseUrl = dotenv.env['BASE_URL']!;
  final _token = dotenv.env['TOKEN']!;
  bool isDownloading = true;
  ValueNotifier<int> downloadProgressNotifier = ValueNotifier(0);
  bool isSearching = false;
  int downloadProgress = 0;
  Timer? _debounceTimer;

  @override
  void initState() {
    super.initState();
    _pdfPathFuture = _fetchPdf();
    _pdfViewerController = PdfViewerController();
    _pdfTextSearchResult = PdfTextSearchResult();
  }

  @override
  void dispose() {
    _pdfTextSearchResult.removeListener(() {});
    _pdfTextSearchResult.dispose();
    _pdfViewerController.dispose();
    _debounceTimer?.cancel();
    super.dispose();
  }

  Future<String> _fetchPdf() async {
    final String pdfFileName = widget.pdf;
    final String baseUrl = '$_baseUrl/assets/$pdfFileName?access_token=$_token';

    final appDir = await getApplicationDocumentsDirectory();
    final pdfDir = Directory(
        '${appDir.path}/LGCC_Search/${context.locale.toString()}/library/');
    if (!await pdfDir.exists()) {
      await pdfDir.create(recursive: true);
    }
    final String filePath = '${pdfDir.path}/$pdfFileName.pdf';
    if (await File(filePath).exists()) {
      return filePath;
    } else {
      try {
        await Dio().download(baseUrl, filePath,
            onReceiveProgress: (actualBytes, totalBytes) {
          final progress = (actualBytes / totalBytes * 100).floor();
          setState(() {
            downloadProgress = progress;
            downloadProgressNotifier.value = progress;
          });
        });
        setState(() {
          isDownloading = false;
        });
        return filePath;
      } catch (e) {
        if (kDebugMode) {
          print('Error downloading file: $e');
        }
        setState(() {
          isDownloading = false;
          downloadProgress = 0;
          downloadProgressNotifier.value = 0;
        });
        return '';
      }
    }
  }

  Future<void> saveDoc() async {
    final List<int> savedBytes = await _pdfViewerController.saveDocument();
    _saveDocument(savedBytes);
  }

  void _performSearch(String searchTerm, {bool immediate = false}) {
    if (mounted && searchTerm.isEmpty) {
      setState(() {
        isSearching = false;
      });
    }
    if (immediate) {
      _performSearchAction(searchTerm);
    } else {
      _debounceTimer?.cancel();
      _debounceTimer = Timer(const Duration(milliseconds: 300), () {
        _performSearchAction(searchTerm);
      });
    }
  }

  void _performSearchAction(String searchTerm) {
    _pdfTextSearchResult = _pdfViewerController.searchText(searchTerm);
    _pdfTextSearchResult.addListener(() {
      if (mounted && _pdfTextSearchResult.isSearchCompleted) {
        setState(() {});
      }
    });
  }

  Future<void> _saveDocument(List<int> dataBytes) async {
    final appDir = await getApplicationDocumentsDirectory();
    final directory = Directory(
        '${appDir.path}/LGCC_Search/${context.locale.toString()}/library/');
    final String path = directory.path;
    final File file = File('$path/${widget.pdf}.pdf');
    await file.writeAsBytes(dataBytes);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: isSearching
              ? TextField(
                  onChanged: (val) => _performSearch(val),
                )
              : Text(widget.title),
          backgroundColor: const Color(0xFFe0e6d1),
          actions: [
            Container(
              margin: const EdgeInsets.only(right: 12),
              child: Row(
                children: [
                  if (_pdfTextSearchResult.hasResult &&
                      _pdfTextSearchResult.totalInstanceCount > 1)
                    Text(
                        '${_pdfTextSearchResult.currentInstanceIndex} / ${_pdfTextSearchResult.totalInstanceCount}'),
                  if (_pdfTextSearchResult.hasResult &&
                      _pdfTextSearchResult.totalInstanceCount > 1)
                    IconButton(
                      icon: const Icon(Icons.chevron_left),
                      onPressed: (_pdfTextSearchResult.currentInstanceIndex > 1)
                          ? () {
                              _pdfTextSearchResult.previousInstance();
                            }
                          : null,
                    ),
                  if (_pdfTextSearchResult.hasResult &&
                      _pdfTextSearchResult.totalInstanceCount > 1)
                    IconButton(
                      icon: const Icon(Icons.chevron_right),
                      onPressed: (_pdfTextSearchResult.currentInstanceIndex <
                              _pdfTextSearchResult.totalInstanceCount)
                          ? () {
                              _pdfTextSearchResult.nextInstance();
                            }
                          : null,
                    ),
                  IconButton(
                    icon: Icon(isSearching ? Icons.close : Icons.search),
                    onPressed: () {
                      setState(() {
                        isSearching = !isSearching;
                      });
                    },
                  ),
                ],
              ),
            )
          ]),
      body: FutureBuilder<String>(
        future: _pdfPathFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(
              child: CircularPercentIndicator(
                backgroundColor: Colors.grey.shade400,
                progressColor: const Color(0xFF6b8e23),
                lineWidth: 3,
                radius: 32,
                center: Text(downloadProgress.toString(),
                    style: const TextStyle(fontSize: 14, color: Colors.black)),
                percent: downloadProgress / 100,
              ),
            );
          } else if (snapshot.hasError) {
            return Center(child: Text('no_results'.tr()));
          } else if (snapshot.hasData) {
            return SfPdfViewer.file(
              File(snapshot.data!),
              controller: _pdfViewerController,
              onDocumentLoaded: (PdfDocumentLoadedDetails details) {
                if (widget.searchTerm != null) {
                  _performSearch(widget.searchTerm!, immediate: true);
                }
              },
              onAnnotationAdded: (annotation) => saveDoc(),
            );
          } else {
            return const Center(child: Text('Error'));
          }
        },
      ),
    );
  }
}
