import 'dart:convert';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart' as desktop;
import 'package:webview_flutter/webview_flutter.dart' as mobile;

import '../../../data/models/file_model.dart';
import '../../../services/api_service.dart';

bool get _useDesktopWebView =>
    !kIsWeb && (Platform.isWindows || Platform.isLinux);

/// 完全交给 Cloudreve 官方 Web 前端处理文件打开。
///
/// 这里不再自己读取 file_viewers，也不再自己创建 viewerSession。
/// Cloudreve 前端本身会根据 `/home?path=...&open=...` 打开对应文件，
/// 并使用它自己的文件应用、WOPI、Markdown、表格、压缩包、EPUB 等逻辑。
class CloudreveFileAppPage extends StatefulWidget {
  final FileModel file;
  final String? preferredAction;

  const CloudreveFileAppPage({
    super.key,
    required this.file,
    this.preferredAction,
  });

  @override
  State<CloudreveFileAppPage> createState() => _CloudreveFileAppPageState();
}

class _CloudreveFileAppPageState extends State<CloudreveFileAppPage> {
  mobile.WebViewController? _mobileController;
  desktop.InAppWebViewController? _desktopController;

  bool _isPreparing = true;
  bool _sessionInjected = false;
  int _progress = 0;
  String? _error;
  late Uri _targetUri;
  late Uri _originUri;
  String? _sessionStateJson;

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

    if (!_useDesktopWebView) {
      _mobileController = mobile.WebViewController()
        ..setJavaScriptMode(mobile.JavaScriptMode.unrestricted)
        ..setBackgroundColor(Colors.transparent)
        ..setNavigationDelegate(
          mobile.NavigationDelegate(
            onProgress: (progress) {
              if (!mounted) return;
              setState(() => _progress = progress);
            },
            onPageFinished: (_) => _injectSessionAndOpenIfNeeded(),
            onWebResourceError: (error) {
              if (!mounted) return;
              if (error.isForMainFrame == true) {
                setState(() {
                  _error = '${error.errorCode}: ${error.description}';
                });
              }
            },
          ),
        );
    }

    _prepareAndOpen();
  }

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

  Future<void> _prepareAndOpen() async {
    setState(() {
      _isPreparing = true;
      _error = null;
      _progress = 0;
      _sessionInjected = false;
      if (_useDesktopWebView) {
        _desktopController = null;
      }
    });

    try {
      _originUri = _buildOriginUri();
      _targetUri = _buildCloudreveHomeUri();

      _sessionStateJson = await _buildCloudreveFrontendSessionJson();

      // 先打开同源页面，再注入 localStorage。
      // 这样 Cloudreve 官方前端可以直接复用 App 的 access_token。
      await _loadOrigin();

      if (!mounted) return;
      setState(() => _isPreparing = false);
    } catch (e) {
      if (!mounted) return;
      setState(() {
        _error = e.toString();
        _isPreparing = false;
      });
    }
  }

  Uri _buildOriginUri() {
    final base = Uri.parse(ApiService.instance.dio.options.baseUrl);
    return Uri(
      scheme: base.scheme,
      host: base.host,
      port: base.hasPort ? base.port : null,
      path: '/',
    );
  }

  Uri _buildCloudreveHomeUri() {
    final parent = _parentUri(widget.file.relativePath);
    final openTarget = widget.file.id.isNotEmpty
        ? widget.file.id
        : widget.file.relativePath;

    return Uri(
      scheme: _originUri.scheme,
      host: _originUri.host,
      port: _originUri.hasPort ? _originUri.port : null,
      path: '/home',
      queryParameters: {
        'path': parent,
        'open': openTarget,
        'size': widget.file.size.toString(),
      },
    );
  }

  String _parentUri(String uri) {
    final normalized = uri.endsWith('/')
        ? uri.substring(0, uri.length - 1)
        : uri;
    final index = normalized.lastIndexOf('/');
    if (index <= 'cloudreve://my'.length) {
      return 'cloudreve://my';
    }
    return normalized.substring(0, index);
  }

  Future<String?> _buildCloudreveFrontendSessionJson() async {
    final tokenGetter = ApiService.instance.getTokenCallback;
    final token = tokenGetter == null ? null : await tokenGetter();
    if (token == null || token.isEmpty) {
      return null;
    }

    Map<String, dynamic>? user;
    try {
      final response = await ApiService.instance.get<Map<String, dynamic>>(
        '/user/me',
      );
      user = Map<String, dynamic>.from(response);
    } catch (_) {
      user = null;
    }

    final userId = user?['id']?.toString() ?? user?['uid']?.toString() ?? 'app';

    final now = DateTime.now().toUtc();
    final accessExpires = now.add(const Duration(hours: 2)).toIso8601String();
    final refreshExpires = now.add(const Duration(hours: 2)).toIso8601String();

    final sessionState = {
      'current': userId,
      'sessions': {
        userId: {
          'user': user ?? {'id': userId},
          'token': {
            'access_token': token,
            // App 侧暂时没有把 refresh token 暴露给这里。
            // 给 Cloudreve 前端一个短期可用 session；过期后 WebView 内刷新会要求重新登录。
            'refresh_token': '',
            'access_expires': accessExpires,
            'refresh_expires': refreshExpires,
          },
          'settings': {},
        },
      },
      'anonymousSettings': {},
    };

    return jsonEncode(sessionState);
  }

  Future<void> _injectSessionAndOpenIfNeeded() async {
    if (_sessionInjected) return;
    _sessionInjected = true;

    final sessionJson = _sessionStateJson;
    final target = _targetUri.toString();

    try {
      if (sessionJson != null) {
        final script =
            '''
          try {
            localStorage.setItem('cloudreve_session', ${jsonEncode(sessionJson)});
          } catch (e) {}
          window.location.replace(${jsonEncode(target)});
        ''';
        await _runJavaScript(script);
      } else {
        await _loadTarget();
      }
    } catch (e) {
      if (!mounted) return;
      setState(() => _error = e.toString());
    }
  }

  Future<void> _openTargetAgain() async {
    _sessionInjected = true;
    await _loadTarget();
  }

  Future<void> _reloadWebView() async {
    if (_useDesktopWebView) {
      await _desktopController?.reload();
    } else {
      await _mobileController?.reload();
    }
  }

  Future<void> _loadOrigin() async {
    if (_useDesktopWebView) {
      final controller = _desktopController;
      if (controller == null) return;
      await _desktopController?.loadUrl(
        urlRequest: desktop.URLRequest(url: desktop.WebUri.uri(_originUri)),
      );
    } else {
      await _mobileController!.loadRequest(_originUri);
    }
  }

  Future<void> _loadTarget() async {
    if (_useDesktopWebView) {
      await _desktopController?.loadUrl(
        urlRequest: desktop.URLRequest(url: desktop.WebUri.uri(_targetUri)),
      );
    } else {
      await _mobileController!.loadRequest(_targetUri);
    }
  }

  Future<void> _runJavaScript(String source) async {
    if (_useDesktopWebView) {
      await _desktopController?.evaluateJavascript(source: source);
    } else {
      await _mobileController!.runJavaScript(source);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.file.name, overflow: TextOverflow.ellipsis),
        actions: [
          IconButton(
            tooltip: '重新打开',
            icon: const Icon(Icons.open_in_browser),
            onPressed: _openTargetAgain,
          ),
          IconButton(
            tooltip: '刷新',
            icon: const Icon(Icons.refresh),
            onPressed: _reloadWebView,
          ),
        ],
        bottom: PreferredSize(
          preferredSize: const Size.fromHeight(3),
          child: _progress > 0 && _progress < 100
              ? LinearProgressIndicator(value: _progress / 100)
              : const SizedBox(height: 3),
        ),
      ),
      body: _buildBody(),
    );
  }

  Widget _buildBody() {
    if (_isPreparing) {
      return const Center(child: CircularProgressIndicator());
    }

    if (_error != null) {
      return Center(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              const Icon(Icons.error_outline, size: 56, color: Colors.red),
              const SizedBox(height: 16),
              Text(_error!, textAlign: TextAlign.center),
              const SizedBox(height: 16),
              FilledButton.icon(
                onPressed: _prepareAndOpen,
                icon: const Icon(Icons.refresh),
                label: const Text('重试'),
              ),
            ],
          ),
        ),
      );
    }

    if (_useDesktopWebView) {
      return desktop.InAppWebView(
        initialSettings: desktop.InAppWebViewSettings(
          javaScriptEnabled: true,
          domStorageEnabled: true,
          transparentBackground: true,
          supportZoom: false,
        ),
        onWebViewCreated: (controller) async {
          _desktopController = controller;
          if (!_isPreparing) {
            await _loadOrigin();
          }
        },
        onProgressChanged: (_, progress) {
          if (!mounted) return;
          setState(() => _progress = progress);
        },
        onLoadStop: (_, url) => _injectSessionAndOpenIfNeeded(),
        onReceivedError: (_, request, error) {
          if (!mounted || request.isForMainFrame != true) return;
          setState(() => _error = '${error.type}: ${error.description}');
        },
      );
    }

    return mobile.WebViewWidget(controller: _mobileController!);
  }
}
