// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

import 'demos.dart';
import 'example_code_parser.dart';
import 'syntax_highlighter.dart';

@immutable
class ComponentDemoTabData {
  const ComponentDemoTabData({
    this.demoWidget,
    this.exampleCodeTag,
    this.description,
    this.tabName,
    this.documentationUrl,
  });

  final Widget? demoWidget;
  final String? exampleCodeTag;
  final String? description;
  final String? tabName;
  final String? documentationUrl;

  @override
  bool operator==(Object other) {
    if (other.runtimeType != runtimeType) {
      return false;
    }
    return other is ComponentDemoTabData
        && other.tabName == tabName
        && other.description == description
        && other.documentationUrl == documentationUrl;
  }

  @override
  int get hashCode => Object.hash(tabName, description, documentationUrl);
}

class TabbedComponentDemoScaffold extends StatefulWidget {
  const TabbedComponentDemoScaffold({
    super.key,
    this.title,
    this.demos,
    this.actions,
    this.isScrollable = true,
    this.showExampleCodeAction = true,
  });

  final List<ComponentDemoTabData>? demos;
  final String? title;
  final List<Widget>? actions;
  final bool isScrollable;
  final bool showExampleCodeAction;

  @override
  State<TabbedComponentDemoScaffold> createState() => _TabbedComponentDemoScaffoldState();
}

class _TabbedComponentDemoScaffoldState extends State<TabbedComponentDemoScaffold> {
  void _showExampleCode(BuildContext context) {
    final String? tag = widget.demos![DefaultTabController.of(context)!.index].exampleCodeTag;
    if (tag != null) {
      Navigator.push(context, MaterialPageRoute<FullScreenCodeDialog>(
        builder: (BuildContext context) => FullScreenCodeDialog(exampleCodeTag: tag)
      ));
    }
  }

  Future<void> _showApiDocumentation(BuildContext context) async {
    final String? url = widget.demos![DefaultTabController.of(context)!.index].documentationUrl;
    if (url == null) {
      return;
    }

    final Uri uri = Uri.parse(url);
    if (await canLaunchUrl(uri)) {
      await launchUrl(uri);
    } else if (mounted) {
      showDialog<void>(
        context: context,
        builder: (BuildContext context) {
          return SimpleDialog(
            title: const Text("Couldn't display URL:"),
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16.0),
                child: Text(url),
              ),
            ],
          );
        },
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: widget.demos!.length,
      child: Scaffold(
        appBar: AppBar(
          title: Text(widget.title!),
          actions: <Widget>[
            ...?widget.actions,
            Builder(
              builder: (BuildContext context) {
                return IconButton(
                  icon: const Icon(Icons.library_books, semanticLabel: 'Show documentation'),
                  onPressed: () => _showApiDocumentation(context),
                );
              },
            ),
            if (widget.showExampleCodeAction)
              Builder(
                builder: (BuildContext context) {
                  return IconButton(
                    icon: const Icon(Icons.code),
                    tooltip: 'Show example code',
                    onPressed: () => _showExampleCode(context),
                  );
                },
              ),
          ],
          bottom: TabBar(
            isScrollable: widget.isScrollable,
            tabs: widget.demos!.map<Widget>((ComponentDemoTabData data) => Tab(text: data.tabName)).toList(),
          ),
        ),
        body: TabBarView(
          children: widget.demos!.map<Widget>((ComponentDemoTabData demo) {
            return SafeArea(
              top: false,
              bottom: false,
              child: Column(
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Text(demo.description!,
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                  ),
                  Expanded(child: demo.demoWidget!),
                ],
              ),
            );
          }).toList(),
        ),
      ),
    );
  }
}

class FullScreenCodeDialog extends StatefulWidget {
  const FullScreenCodeDialog({ super.key, this.exampleCodeTag });

  final String? exampleCodeTag;

  @override
  FullScreenCodeDialogState createState() => FullScreenCodeDialogState();
}

class FullScreenCodeDialogState extends State<FullScreenCodeDialog> {

  String? _exampleCode;

  @override
  void didChangeDependencies() {
    getExampleCode(widget.exampleCodeTag, DefaultAssetBundle.of(context)).then((String? code) {
      if (mounted) {
        setState(() {
          _exampleCode = code ?? 'Example code not found';
        });
      }
    });
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    final SyntaxHighlighterStyle style = Theme.of(context).brightness == Brightness.dark
      ? SyntaxHighlighterStyle.darkThemeStyle()
      : SyntaxHighlighterStyle.lightThemeStyle();

    Widget body;
    if (_exampleCode == null) {
      body = const Center(
        child: CircularProgressIndicator(),
      );
    } else {
      body = SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: RichText(
            text: TextSpan(
              style: const TextStyle(fontFamily: 'monospace', fontSize: 10.0),
              children: <TextSpan>[
                DartSyntaxHighlighter(style).format(_exampleCode),
              ],
            ),
          ),
        ),
      );
    }

    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: const Icon(
            Icons.clear,
            semanticLabel: 'Close',
          ),
          onPressed: () { Navigator.pop(context); },
        ),
        title: const Text('Example code'),
      ),
      body: body,
    );
  }
}

class MaterialDemoDocumentationButton extends StatelessWidget {
  MaterialDemoDocumentationButton(String routeName, { super.key })
    : documentationUrl = kDemoDocumentationUrl[routeName],
      assert(
        kDemoDocumentationUrl[routeName] != null,
        'A documentation URL was not specified for demo route $routeName in kAllGalleryDemos',
      );

  final String? documentationUrl;

  @override
  Widget build(BuildContext context) {
    return IconButton(
      icon: const Icon(Icons.library_books),
      tooltip: 'API documentation',
      onPressed: () => launchUrl(Uri.parse(documentationUrl!), mode: LaunchMode.inAppWebView),
    );
  }
}

class CupertinoDemoDocumentationButton extends StatelessWidget {
  CupertinoDemoDocumentationButton(String routeName, { super.key })
    : documentationUrl = kDemoDocumentationUrl[routeName],
      assert(
        kDemoDocumentationUrl[routeName] != null,
        'A documentation URL was not specified for demo route $routeName in kAllGalleryDemos',
      );

  final String? documentationUrl;

  @override
  Widget build(BuildContext context) {
    return CupertinoButton(
      padding: EdgeInsets.zero,
      child: Semantics(
        label: 'API documentation',
        child: const Icon(CupertinoIcons.book),
      ),
      onPressed: () => launchUrl(Uri.parse(documentationUrl!), mode: LaunchMode.inAppWebView),
    );
  }
}
