// Copyright 2019 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/material.dart';
import 'package:provider/provider.dart';

import 'navigation_drawer.dart';
import 'state/agent.dart';
import 'widgets/agent_list.dart';
import 'widgets/app_bar.dart';
import 'widgets/error_brook_watcher.dart';
import 'widgets/progress_button.dart';

/// Shows current status of Flutter infra agents.
///
/// If [agentFilter] is non-null and non-empty, it will only show agents
/// with [agentId] that contains [agentFilter]. Otherwise, all agents are shown.
class AgentDashboardPage extends StatelessWidget {
  const AgentDashboardPage({
    Key key,
    this.agentFilter,
  }) : super(key: key);

  /// Search term to filter the agents from [agentState] and show only those
  /// that contain this term.
  ///
  /// If this is null, the [Route.arguments] value is used instead.
  final String agentFilter;

  static const String routeName = '/agents';

  static void _showCreateAgentDialog(BuildContext context, AgentState agentState) {
    showDialog<AlertDialog>(
      context: context,
      builder: (BuildContext context) => CreateAgentDialog(agentState: agentState),
    );
  }

  @override
  Widget build(BuildContext context) {
    final AgentState _agentState = Provider.of<AgentState>(context);
    return AnimatedBuilder(
      animation: _agentState,
      builder: (BuildContext context, Widget child) => Scaffold(
        appBar: const CocoonAppBar(
          title: Text('Infra Agents'),
        ),
        body: ErrorBrookWatcher(
          errors: _agentState.errors,
          child: Align(
            alignment: Alignment.topCenter,
            child: SizedBox(
              width: 500,
              child: AgentList(
                // TODO(ianh): stop passing both the state and the value from the state
                agents: _agentState.agents,
                agentState: _agentState,
                agentFilter: agentFilter ?? ModalRoute.of(context).settings.arguments as String,
              ),
            ),
          ),
        ),
        drawer: const NavigationDrawer(),
        floatingActionButton: FloatingActionButton.extended(
          icon: const Icon(Icons.add),
          label: const Text('CREATE AGENT'),
          onPressed: () => _showCreateAgentDialog(context, _agentState),
        ),
      ),
    );
  }
}

/// Dialog with a form that has inputs necessary for creating an agent.
///
/// User must input an agent id and a list of capabilities to create an agent.
/// Capabilities are inputted as a comma delimited list.
class CreateAgentDialog extends StatefulWidget {
  const CreateAgentDialog({
    Key key,
    this.agentState,
  }) : super(key: key);

  final AgentState agentState;

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

class _CreateAgentDialogState extends State<CreateAgentDialog> {
  TextEditingController _agentIdController;
  TextEditingController _agentCapabilitiesController;

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

    _agentIdController = TextEditingController();
    _agentCapabilitiesController = TextEditingController();
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: const Text('Create Agent'),
      content: Form(
        child: SizedBox(
          height: 200,
          child: Column(
            children: <Widget>[
              TextFormField(
                controller: _agentIdController,
                decoration: const InputDecoration(
                  hintText: 'Enter agent id',
                ),
                validator: (String value) {
                  if (value.isEmpty) {
                    return 'Please enter an agent id (e.g. flutter-devicelab-linux-14)';
                  }
                  return null;
                },
              ),
              TextFormField(
                controller: _agentCapabilitiesController,
                decoration: const InputDecoration(
                  hintText: 'Enter agent capabilities',
                ),
                validator: (String value) {
                  if (value.split(',').isEmpty) {
                    return 'Please enter agent capabilities as comma delimited list (e.g. linux,linux/android)';
                  }

                  return value;
                },
              ),
              Container(height: 25),
              ProgressButton(
                child: const Text('Create'),
                onPressed: () => _createAgent(context),
              )
            ],
          ),
        ),
      ),
    );
  }

  /// Send a request to Cocoon to create an agent with the values inputted
  /// to the form.
  Future<void> _createAgent(BuildContext context) async {
    final String id = _agentIdController.value.text;
    final List<String> capabilities = _agentCapabilitiesController.value.text.split(',');
    final String token = await widget.agentState.createAgent(id, capabilities);

    // TODO(chillers): Copy the token to clipboard when web has support. https://github.com/flutter/flutter/issues/46020
    debugPrint('$id: $token');
    debugPrint('Capabilities: $capabilities');

    Navigator.pop(context);
  }
}
