# -*- coding: utf-8 -*- #
# Copyright 2016 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Create command for gcloud debug snapshots command group."""

from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals

from googlecloudsdk.api_lib.debug import debug
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core import properties

DETAILED_HELP = {
    'brief':
        """\
        Create debug snapshots for a Cloud Debugger debug target (debuggee).
    """,
    'DESCRIPTION':
        """\
        *{command}* is used to create a debug snapshot on a Cloud Debugger debug
        target. Snapshots allow you to capture stack traces and local variables
        from your running service without interfering with normal operations.

        When any instance of the target executes the snapshot location, the
        optional condition expression is evaluated. If the result is true (or if
        there is no condition), the instance captures the current thread state
        and reports it back to Cloud Debugger. Once any instance captures a
        snapshot, the snapshot is marked as completed, and it will not be
        captured again.

        You can view snapshot results in the developer console. It is also
        possible to inspect snapshot results with the "snapshots describe"
        command.
    """,
    'EXAMPLES':
        """\
        To create a snapshot with no conditions or expressions at line 41 of
        file main.py of a debug target (debuggee), run:

          $ {command} main.py:41 --target=<debuggee_id>

        To create a snapshot at line 41 of file main.py on a debug target
        (debuggee) that will only trigger if the variable name has the value of
        'foo', run:

          $ {command} main.py:41 --target=<debuggee_id> --condition="name == 'foo'"

        To create a snapshot at line 41 of file main.py on a debug target
        (debuggee) with the expressions name[0] and name[1], run:

          $ {command} main.py:41 --target=<debuggee_id> --expression="name[0]" --expression="name[1]"
    """
}


class Create(base.CreateCommand):
  """Create debug snapshots."""

  detailed_help = DETAILED_HELP

  @staticmethod
  def Args(parser):
    parser.add_argument(
        'location',
        help="""\
            The location where the snapshot should be taken. Locations are of
            the form FILE:LINE, where FILE can be simply the file name, or the
            file name preceded by enough path components to differntiate it from
            other files with the same name. If the file name is not unique in
            the debug target, the behavior is unspecified.
        """)
    parser.add_argument(
        '--condition',
        help="""\
            A condition to restrict when the snapshot is taken. When the
            snapshot location is executed, the condition will be evaluated, and
            the snapshot will be generated only if the condition is true.
        """)
    parser.add_argument(
        '--expression', action='append',
        help="""\
            An expression to evaluate when the snapshot is taken. You may
            specify --expression multiple times.
        """)
    parser.add_argument(
        '--wait', default=10,
        help="""\
            The number of seconds to wait to ensure that no error is returned
            from a debugger agent when creating the snapshot. When a snapshot
            is created, there will be a delay before the agents see and apply
            the snapshot. Until at least one agent has attempted to
            enable the snapshot, it cannot be determined if the snapshot is
            valid.
        """)
    parser.display_info.AddFormat("""
          list(
            format("id: {0}", id),
            format("location: {0}", location),
            format("status: {0}", full_status()),
            format("consoleViewUrl: {0}", consoleViewUrl)
          )
    """)

  def Run(self, args):
    """Run the create command."""
    project_id = properties.VALUES.core.project.Get(required=True)
    user_email = properties.VALUES.core.account.Get(required=True)
    debugger = debug.Debugger(project_id)
    debuggee = debugger.FindDebuggee(args.target)
    snapshot = debuggee.CreateSnapshot(
        location=args.location, expressions=args.expression,
        condition=args.condition, user_email=user_email)
    final_snapshot = debuggee.WaitForBreakpointSet(snapshot.id, args.wait,
                                                   args.location)
    if args.location != final_snapshot.location:
      log.status.write(
          'The debugger adjusted the snapshot location to {0}'.format(
              final_snapshot.location))
    return final_snapshot or snapshot
