#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
#

"""A portable "runner" that renders a beam graph.

This runner can either render the graph to a (set of) output path(s), as
designated by (possibly repeated) --render_output, or serve the pipeline as
an interactive graph, if --render_port is set.

In Python, this runner can be passed directly at pipeline construction, e.g.::

   with beam.Pipeline(runner=beam.runners.render.RenderRunner(), options=...)

For other languages, start this service a by running::

  python -m apache_beam.runners.render --job_port=PORT ...

and then run your pipline with the PortableRunner setting the job endpoint
to `localhost:PORT`.

If any `--render_output=path.ext` flags are passed, each submitted job will
get written to the given output (overwriting any previously existing file).

If `--render_port` is set to a non-negative value, a local http server will
be started which allows for interactive exploration of the pipeline graph.

As an alternative to starting a job server, a single pipeline can be rendered
by passing a pipeline proto file to `--pipeline_proto`.  For example

  python -m apache_beam.runners.render  \\
      --pipeline_proto gs://<staging_location>/pipeline.pb  \\
      --render_output=/tmp/pipeline.svg

Requires the graphviz dot executable to be available in the path.
"""

import argparse
import base64
import collections
import http.server
import json
import logging
import os
import re
import subprocess
import sys
import tempfile
import threading
import time
import urllib.parse

from google.protobuf import json_format
from google.protobuf import text_format

from apache_beam.options import pipeline_options
from apache_beam.portability.api import beam_runner_api_pb2
from apache_beam.runners import runner
from apache_beam.runners.portability import local_job_service
from apache_beam.runners.portability import local_job_service_main
from apache_beam.runners.portability.fn_api_runner import translations

try:
  from apache_beam.io.gcp import gcsio
except ImportError:
  gcsio = None  # type: ignore

_LOGGER = logging.getLogger(__name__)

# From the Beam site, circa November 2022.
DEFAULT_EDGE_STYLE = 'color="#ff570b"'
DEFAULT_TRANSFORM_STYLE = (
    'shape=rect style="rounded, filled" color="#ff570b" fillcolor="#fff6dd"')
DEFAULT_HIGHLIGHT_STYLE = (
    'shape=rect style="rounded, filled" color="#ff570b" fillcolor="#ffdb97"')


class RenderOptions(pipeline_options.PipelineOptions):
  """Rendering options."""
  @classmethod
  def _add_argparse_args(cls, parser):
    parser.add_argument(
        '--render_port',
        type=int,
        default=-1,
        help='The port at which to serve the graph. '
        'If 0, an unused port will be chosen. '
        'If -1, the server will not be started.')
    parser.add_argument(
        '--render_output',
        action='append',
        help='A path or paths to which to write rendered output. '
        'The output type will be deduced from the file extension.')
    parser.add_argument(
        '--render_leaf_composite_nodes',
        action='append',
        help='A set of regular expressions for transform names that should '
        'not be expanded.  For example, one could pass "\bRead.*" to indicate '
        'the inner structure of read nodes should not be expanded. '
        'If not given, defaults to the top-level nodes if interactively '
        'serving the graph and expanding all nodes otherwise.')
    parser.add_argument(
        '--render_edge_attributes',
        default='',
        help='Graphviz attributes to add to all edges.')
    parser.add_argument(
        '--render_node_attributes',
        default='',
        help='Graphviz attributes to add to all nodes.')
    parser.add_argument(
        '--render_highlight_attributes',
        default='',
        help='Graphviz attributes to add to all highlighted nodes.')
    parser.add_argument(
        '--log_proto',
        default=False,
        action='store_true',
        help='Set to also log input pipeline proto to stdout.')
    return parser


class PipelineRenderer:
  def __init__(self, pipeline, options):
    self.pipeline = pipeline
    self.options = options

    # Drill down into any uninteresting, top-level transforms that contain
    # the whole pipeline (often added by the SDK).
    roots = self.pipeline.root_transform_ids
    while len(roots) == 1:
      root = self.pipeline.components.transforms[roots[0]]
      if not root.subtransforms:
        break
      roots = root.subtransforms
    self.roots = roots

    # Figure out at what point to stop rendering composite internals.
    if options.render_leaf_composite_nodes:
      is_leaf = lambda transform_id: any(
          re.match(
              pattern, self.pipeline.components.transforms[transform_id].
              unique_name) for patterns in options.render_leaf_composite_nodes
          for pattern in patterns.split(','))
      self.leaf_composites = set()

      def mark_leaves(transform_ids):
        for transform_id in transform_ids:
          if is_leaf(transform_id):
            self.leaf_composites.add(transform_id)
          else:
            mark_leaves(
                self.pipeline.components.transforms[transform_id].subtransforms)

      mark_leaves(self.roots)

    elif options.render_port >= 0:
      # Start interactive with no unfolding.
      self.leaf_composites = set(self.roots)
    else:
      # For non-interactive, expand fully.
      self.leaf_composites = set()

    # Useful for attempting graph layout consistency.
    self.latest_positions = {}
    self.highlighted = []

  def update(self, toggle=None):
    if toggle:
      transform_id = toggle[0]
      self.highlighted = [transform_id]
      if transform_id in self.leaf_composites:
        transform = self.pipeline.components.transforms[transform_id]
        if transform.subtransforms:
          self.leaf_composites.remove(transform_id)
          for subtransform in transform.subtransforms:
            self.leaf_composites.add(subtransform)
            if transform_id in self.latest_positions:
              self.latest_positions[subtransform] = self.latest_positions[
                  transform_id]
      else:
        self.leaf_composites.add(transform_id)

  def style(self, transform_id):
    base = ' '.join(
        [DEFAULT_TRANSFORM_STYLE, self.options.render_node_attributes])
    if transform_id in self.highlighted:
      return ' '.join([
          base,
          DEFAULT_HIGHLIGHT_STYLE,
          self.options.render_highlight_attributes
      ])
    else:
      return base

  def to_dot(self):
    return '\n'.join(self.to_dot_iter())

  def to_dot_iter(self):
    yield 'digraph G {'
    # Defer drawing any edges until the end lest we declare nodes too early.
    edges_out = []
    for transform_id in self.roots:
      yield from self.transform_to_dot(
          transform_id, self.pcoll_leaf_consumers(), edges_out)
    yield from edges_out
    yield '}'

  def transform_to_dot(self, transform_id, pcoll_leaf_consumers, edges_out):
    transform = self.pipeline.components.transforms[transform_id]
    if self.is_leaf(transform_id):
      yield self.transform_node(transform_id)
      transform_inputs = set(transform.inputs.values())
      for name, output in transform.outputs.items():
        # For outputs that are also inputs, it's ambiguous whether they are
        # consumed as the outputs of this transform, or of the upstream
        # transform. Render the latter.
        if output in transform_inputs:
          continue
        output_label = name if len(transform.outputs) > 1 else ''
        for consumer, is_side_input in pcoll_leaf_consumers[output]:
          # Can't yield this here as the consumer might not be in this cluster.
          edge_style = 'dashed' if is_side_input else 'solid'
          edge_attributes = ' '.join([
              f'label="{output_label}" style={edge_style}',
              DEFAULT_EDGE_STYLE,
              self.options.render_edge_attributes
          ])
          edges_out.append(
              f'"{transform_id}" -> "{consumer}" [{edge_attributes}]')
    else:
      yield f'subgraph "cluster_{transform_id}" {{'
      yield self.transform_attributes(transform_id)
      for subtransform in transform.subtransforms:
        yield from self.transform_to_dot(
            subtransform, pcoll_leaf_consumers, edges_out)
      yield '}'

  def transform_node(self, transform_id):
    return f'"{transform_id}" [{self.transform_attributes(transform_id)}]'

  def transform_attributes(self, transform_id):
    transform = self.pipeline.components.transforms[transform_id]
    local_name = transform.unique_name.split('/')[-1]
    if transform_id in self.latest_positions:
      pos_str = f'pos="{self.latest_positions[transform_id]}"'
    else:
      pos_str = ''
    return (
        f'label="{local_name}" {self.style(transform_id)} '
        f'URL="javascript:click(\'{transform_id}\')" {pos_str}')

  def pcoll_leaf_consumers_iter(self, transform_id):
    transform = self.pipeline.components.transforms[transform_id]
    transform_inputs = set(transform.inputs.values())
    side_inputs = set(translations.side_inputs(transform).values())
    if self.is_leaf(transform_id):
      for pcoll in transform.inputs.values():
        yield pcoll, (transform_id, pcoll in side_inputs)
    for subtransform in transform.subtransforms:
      for pcoll, (consumer,
                  annotation) in self.pcoll_leaf_consumers_iter(subtransform):
        if self.is_leaf(transform_id):
          if pcoll not in transform_inputs:
            yield pcoll, (transform_id, annotation)
        else:
          yield pcoll, (consumer, annotation)

  def pcoll_leaf_consumers(self):
    result = collections.defaultdict(list)
    for transform_id in self.roots:
      for pcoll, consumer_info in self.pcoll_leaf_consumers_iter(transform_id):
        result[pcoll].append(consumer_info)
    return result

  def is_leaf(self, transform_id):
    return (
        transform_id in self.leaf_composites or
        not self.pipeline.components.transforms[transform_id].subtransforms)

  def info(self):
    if len(self.highlighted) != 1:
      return ''
    transform_id = self.highlighted[0]
    return f'<pre>{self.pipeline.components.transforms[transform_id]}</pre>'

  def layout_dot(self):
    layout = subprocess.run(['dot', '-Tdot'],
                            input=self.to_dot().encode('utf-8'),
                            capture_output=True,
                            check=True).stdout

    # Try to capture the positions for layout consistency.
    json_out = json.loads(
        subprocess.run(['dot', '-n2', '-Kneato', '-Tjson'],
                       input=layout,
                       capture_output=True,
                       check=True).stdout)
    for box in json_out['objects']:
      name = box.get('name', None)
      if name in self.pipeline.components.transforms:
        if 'pos' in box:
          self.latest_positions[name] = box['pos']
        elif 'bb' in box:
          x0, y0, x1, y1 = [float(r) for r in box['bb'].split(',')]
          self.latest_positions[name] = f'{(x0+x1)/2},{(y0+y1)/2}'

    return layout

  def page_callback_data(self, layout):
    svg = subprocess.run(['dot', '-Kneato', '-n2', '-Tsvg'],
                         input=layout,
                         capture_output=True,
                         check=True).stdout
    cmapx = subprocess.run(['dot', '-Kneato', '-n2', '-Tcmapx'],
                           input=layout,
                           capture_output=True,
                           check=True).stdout

    return {
        'src': 'data:image/svg+xml;base64,' +
        base64.b64encode(svg).decode('utf-8'),
        'cmapx': cmapx.decode('utf-8'),
        'info': self.info(),
    }

  def render_data(self):
    _LOGGER.info("Re-rendering pipeline...")
    layout = self.layout_dot()
    if self.options.render_output:
      for path in self.options.render_output:
        format = os.path.splitext(path)[-1][1:]
        result = subprocess.run(
            ['dot', '-Kneato', '-n2', '-T' + format, '-o', path],
            input=layout,
            check=False)
        if result.returncode:
          _LOGGER.error(
              "Failed render pipeline as %r: exit %s", path, result.returncode)
        else:
          _LOGGER.info("Rendered pipeline as %r", path)
    return self.page_callback_data(layout)

  def render_json(self):
    return json.dumps(self.render_data())

  def page(self):
    data = self.render_data()
    src = data['src']
    cmapx = data['cmapx']
    return """
        <html>
          <head>
          <script>
            function click(transform_id) {
              var xhttp = new XMLHttpRequest();
              xhttp.onreadystatechange = function() {
                render_data = JSON.parse(this.responseText);
                document.getElementById('image_map_holder').innerHTML =
                    render_data.cmapx;
                document.getElementById('image_tag').src = render_data.src
                document.getElementById('info').innerHTML = render_data.info
              };
              xhttp.open("GET", "render?toggle=" + transform_id, true);
              xhttp.send();
            }

          </script>
          </head>
          """ + f"""
          <body>
            Click on a composite transform to expand.
            <br>
            <img id='image_tag' src='{src}' usemap='#G'>
            <hr>
            <div id='info'></div>
            <div id='image_map_holder'>
            {cmapx}
            </div>
          </body>
        </html>
    """


class RenderRunner(runner.PipelineRunner):
  # TODO(robertwb): Consider making this a runner wrapper, where live status
  # (such as counters, stage completion status, or possibly even PCollection
  # samples) queryable and/or displayed.  This could evolve into a full Beam
  # UI.
  def run_pipeline(self, pipeline_object, options):
    return self.run_portable_pipeline(pipeline_object.to_runner_api(), options)

  def run_portable_pipeline(self, pipeline_proto, options):
    render_options = options.view_as(RenderOptions)
    if render_options.render_port < 0 and not render_options.render_output:
      raise ValueError(
          'At least one of --render_port or --render_output must be provided.')
    if render_options.log_proto:
      _LOGGER.info(pipeline_proto)
    renderer = PipelineRenderer(pipeline_proto, render_options)
    try:
      subprocess.run(['dot', '-V'], capture_output=True, check=True)
    except FileNotFoundError as exn:
      # If dot is not available, we can at least output the raw .dot files.
      dot_files = [
          output for output in render_options.render_output
          if output.endswith('.dot')
      ]
      for output in dot_files:
        with open(output, 'w') as fout:
          fout.write(renderer.to_dot())
          _LOGGER.info("Wrote pipeline as %s", output)

      non_dot_files = set(render_options.render_output) - set(dot_files)
      if non_dot_files:
        raise RuntimeError(
            "Graphviz dot executable not available "
            f"for rendering non-dot output files {non_dot_files}") from exn
      elif render_options.render_port >= 0:
        raise RuntimeError(
            "Graphviz dot executable not available for serving") from exn

      return RenderPipelineResult(None)

    renderer.page()

    if render_options.render_port >= 0:
      # TODO: If this gets more complex, we could consider taking on a
      # framework like Flask as a dependency.
      class RequestHandler(http.server.BaseHTTPRequestHandler):
        def do_GET(self):
          parts = urllib.parse.urlparse(self.path)
          args = urllib.parse.parse_qs(parts.query)
          renderer.update(**args)

          if parts.path == '/':
            response = renderer.page()
          elif parts.path == '/render':
            response = renderer.render_json()
          else:
            self.send_response(400)
            return

          self.send_response(200)
          self.send_header("Content-type", "text/html")
          self.end_headers()
          self.wfile.write(response.encode('utf-8'))

      server = http.server.HTTPServer(('localhost', render_options.render_port),
                                      RequestHandler)
      server_thread = threading.Thread(target=server.serve_forever, daemon=True)
      server_thread.start()
      print('Serving at http://%s:%s' % server.server_address)
      return RenderPipelineResult(server)

    else:
      return RenderPipelineResult(None)


class RenderPipelineResult(runner.PipelineResult):
  def __init__(self, server):
    super().__init__(runner.PipelineState.RUNNING)
    self.server = server

  def wait_until_finish(self, duration=None):
    if self.server:
      time.sleep(duration or 1e8)
      self.server.shutdown()
    self._state = runner.PipelineState.DONE

  def monitoring_infos(self):
    return []


def run(argv):
  if argv[0] == __file__:
    argv = argv[1:]
  parser = argparse.ArgumentParser(
      description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
  parser.add_argument(
      '--job_port',
      type=int,
      default=0,
      help='port on which to serve the job api')
  parser.add_argument(
      '--pipeline_proto', help='file containing the beam pipeline definition')
  RenderOptions._add_argparse_args(parser)
  options = parser.parse_args(argv)

  if options.pipeline_proto:
    if not options.render_output and options.render_port < 0:
      options.render_port = 0

    render_one(options)

    if options.render_output:
      return

  run_server(options)


def render_one(options):
  if options.pipeline_proto == '-':
    content = sys.stdin.buffer.read()
    if content[0] == b'{':
      ext = '.json'
    else:
      try:
        content.decode('utf-8')
        ext = '.textproto'
      except UnicodeDecodeError:
        ext = '.pb'
  else:
    if options.pipeline_proto.startswith('gs://'):
      if gcsio is None:
        raise ImportError('GCS not available; please install apache_beam[gcp]')
      open_fn = gcsio.GcsIO().open
    else:
      open_fn = open

    with open_fn(options.pipeline_proto, 'rb') as fin:
      content = fin.read()
    ext = os.path.splitext(options.pipeline_proto)[-1]

  if ext == '.textproto':
    pipeline_proto = text_format.Parse(content, beam_runner_api_pb2.Pipeline())
  elif ext == '.json':
    pipeline_proto = json_format.Parse(content, beam_runner_api_pb2.Pipeline())
  else:
    pipeline_proto = beam_runner_api_pb2.Pipeline()
    pipeline_proto.ParseFromString(content)

  RenderRunner().run_portable_pipeline(
      pipeline_proto, pipeline_options.PipelineOptions(**vars(options)))


def run_server(options):
  class RenderBeamJob(local_job_service.BeamJob):
    def _invoke_runner(self):
      return RenderRunner().run_portable_pipeline(
          self._pipeline_proto,
          pipeline_options.PipelineOptions(**vars(options)))

  with tempfile.TemporaryDirectory() as staging_dir:
    job_servicer = local_job_service.LocalJobServicer(
        staging_dir, beam_job_type=RenderBeamJob)
    port = job_servicer.start_grpc_server(options.job_port)
    try:
      local_job_service_main.serve("Listening for beam jobs on port %d." % port)
    finally:
      job_servicer.stop()


if __name__ == '__main__':
  logging.basicConfig()
  logging.getLogger().setLevel(logging.INFO)
  run(sys.argv)
