<!--
  ~ 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.
  -->

<nz-tabset
  *ngIf="checkPointStats"
  [nzSize]="'small'"
  [nzAnimated]="{ inkBar: true, tabPane: false }"
  [nzTabBarExtraContent]="extraTemplate"
>
  <nz-tab nzTitle="Overview">
    <nz-table
      class="no-border small"
      [nzData]="checkPointStats['latest'] ? [''] : []"
      [nzSize]="'small'"
      [nzFrontPagination]="false"
      [nzShowPagination]="false"
    >
      <tbody>
        <ng-container *ngIf="checkPointStats['latest'] && checkPointStats['counts']">
          <tr>
            <td><strong>Checkpoint Counts</strong></td>
            <td>
              <span>
                <strong>Triggered:</strong>
                {{ checkPointStats['counts']['total'] }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>In Progress:</strong>
                {{ checkPointStats['counts']['in_progress'] }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Completed:</strong>
                {{ checkPointStats['counts']['completed'] }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Failed:</strong>
                {{ checkPointStats['counts']['failed'] }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Restored:</strong>
                {{ checkPointStats['counts']['restored'] }}
              </span>
            </td>
          </tr>
          <tr>
            <td><strong>Latest Completed Checkpoint</strong></td>
            <td *ngIf="checkPointStats['latest']['completed']">
              <span>
                <strong>ID:</strong>
                {{ checkPointStats['latest']['completed']['id'] }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Completion Time:</strong>
                {{
                  checkPointStats['latest']['completed']['latest_ack_timestamp']
                    | date: 'yyyy-MM-dd HH:mm:ss.SSS'
                }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>End to End Duration:</strong>
                {{
                  checkPointStats['latest']['completed']['end_to_end_duration'] | humanizeDuration
                }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Checkpointed Data Size:</strong>
                {{ checkPointStats['latest']['completed']['checkpointed_size'] | humanizeBytes }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Full Checkpoint Data Size:</strong>
                {{ checkPointStats['latest']['completed']['state_size'] | humanizeBytes }}
              </span>
            </td>
            <td *ngIf="!checkPointStats['latest']['completed']">None</td>
          </tr>
          <tr *ngIf="checkPointStats['latest']['completed']">
            <td colspan="2" class="collapse-td">
              <flink-job-checkpoints-detail
                [checkPoint]="checkPointStats['latest']['completed']"
              ></flink-job-checkpoints-detail>
            </td>
          </tr>
          <tr>
            <td><strong>Latest Failed Checkpoint</strong></td>
            <td *ngIf="checkPointStats['latest']['failed']">
              <span>
                <strong>ID:</strong>
                {{ checkPointStats['latest']['failed']['id'] }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Failure Time:</strong>
                {{
                  checkPointStats['latest']['failed']['failure_timestamp']
                    | date: 'yyyy-MM-dd HH:mm:ss.SSS'
                }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong *ngIf="checkPointStats['latest']['failed']['failure_message']">
                  Cause:
                </strong>
                {{ checkPointStats['latest']['failed']['failure_message'] }}
              </span>
              <span *ngIf="!checkPointStats['latest']['failed']['failure_message']">
                <strong>Cause:</strong>
                n/a
              </span>
            </td>
            <td *ngIf="!checkPointStats['latest']['failed']">None</td>
          </tr>
          <tr *ngIf="checkPointStats['latest']['failed']">
            <td colspan="2" class="collapse-td">
              <flink-job-checkpoints-detail
                [checkPoint]="checkPointStats['latest']['failed']"
              ></flink-job-checkpoints-detail>
            </td>
          </tr>
          <tr>
            <td><strong>Latest Savepoint</strong></td>
            <td *ngIf="checkPointStats['latest']['savepoint']">
              <span>
                <strong>ID:</strong>
                {{ checkPointStats['latest']['savepoint']['id'] }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Completion Time:</strong>
                {{
                  checkPointStats['latest']['savepoint']['latest_ack_timestamp']
                    | date: 'yyyy-MM-dd HH:mm:ss.SSS'
                }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Checkpointed Data Size:</strong>
                {{ checkPointStats['latest']['savepoint']['checkpointed_size'] | humanizeBytes }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Full Checkpoint Data Size:</strong>
                {{ checkPointStats['latest']['savepoint']['state_size'] | humanizeBytes }}
              </span>
              <ng-container *ngIf="checkPointStats['latest']['savepoint']['savepointFormat']">
                <nz-divider nzType="vertical"></nz-divider>
                <strong>Savepoint Format:</strong>
                {{ checkPointStats['latest']['savepoint']['savepointFormat'] }}
              </ng-container>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Path:</strong>
                {{ checkPointStats['latest']['savepoint']['external_path'] }}
              </span>
            </td>
            <td *ngIf="!checkPointStats['latest']['savepoint']">None</td>
          </tr>
          <tr *ngIf="checkPointStats['latest']['savepoint']">
            <td colspan="2" class="collapse-td">
              <flink-job-checkpoints-detail
                [checkPoint]="checkPointStats['latest']['savepoint']"
              ></flink-job-checkpoints-detail>
            </td>
          </tr>
          <tr>
            <td><strong>Latest Restore</strong></td>
            <td *ngIf="checkPointStats['latest']['restored']">
              <span>
                <strong>ID:</strong>
                {{ checkPointStats['latest']['restored']['id'] }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong>Restore Time:</strong>
                {{
                  checkPointStats['latest']['restored']['restore_timestamp']
                    | date: 'yyyy-MM-dd HH:mm:ss.SSS'
                }}
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span *ngIf="checkPointStats['latest']['restored']['is_savepoint']">
                <strong>Type:</strong>
                Savepoint
              </span>
              <span *ngIf="!checkPointStats['latest']['restored']['is_savepoint']">
                <strong>Type:</strong>
                Checkpoint
              </span>
              <nz-divider nzType="vertical"></nz-divider>
              <span>
                <strong *ngIf="checkPointStats['latest']['restored']['external_path']">
                  Path:
                </strong>
                {{ checkPointStats['latest']['restored']['external_path'] }}
              </span>
            </td>
            <td *ngIf="!checkPointStats['latest']['restored']">None</td>
          </tr>
        </ng-container>
      </tbody>
    </nz-table>
  </nz-tab>
  <nz-tab nzTitle="History">
    <nz-table
      class="no-border small"
      [nzSize]="'small'"
      [nzData]="checkPointStats['history'] || []"
      [nzFrontPagination]="false"
      [nzShowPagination]="false"
    >
      <thead>
        <tr>
          <th nzWidth="70px"></th>
          <th><strong>ID</strong></th>
          <th><strong>Status</strong></th>
          <th><strong>Acknowledged</strong></th>
          <th><strong>Trigger Time</strong></th>
          <th><strong>Latest Acknowledgement</strong></th>
          <th><strong>End to End Duration</strong></th>
          <th>
            <strong>
              Checkpointed Data Size
              <i
                class="header-icon"
                nz-icon
                nz-tooltip
                nzTooltipTitle="The size of data persisted during the sync and async phases of a checkpoint. It's usually smaller than Full checkpoint data size if incremental checkpoints or changelog is enabled."
                nzType="info-circle"
              ></i>
            </strong>
          </th>
          <th><strong>Full Checkpoint Data Size</strong></th>
          <th><strong>Processed (persisted) in-flight data</strong></th>
        </tr>
      </thead>
      <tbody>
        <ng-container *ngFor="let checkpoint of checkPointStats['history']; trackBy: trackById">
          <tr>
            <td nzShowExpand [(nzExpand)]="checkpoint.expand"></td>
            <td>{{ checkpoint['id'] }}</td>
            <td>
              <flink-checkpoint-badge [state]="checkpoint['status']">
                {{ checkpoint['status'] }}
                <em *ngIf="checkpoint['is_savepoint']">[Savepoint]</em>
              </flink-checkpoint-badge>
            </td>

            <td>
              {{ checkpoint['num_acknowledged_subtasks'] }}/{{ checkpoint['num_subtasks'] }}
              <span *ngIf="checkpoint['status'] === 'IN_PROGRESS'">
                ({{
                  checkpoint['num_acknowledged_subtasks'] / checkpoint['num_subtasks'] | percent
                }})
              </span>
            </td>
            <td>{{ checkpoint['trigger_timestamp'] | date: 'yyyy-MM-dd HH:mm:ss.SSS' }}</td>
            <td *ngIf="checkpoint['latest_ack_timestamp'] >= 0">
              {{ checkpoint['latest_ack_timestamp'] | date: 'yyyy-MM-dd HH:mm:ss.SSS' }}
            </td>
            <td *ngIf="checkpoint['latest_ack_timestamp'] < 0">n/a</td>
            <td *ngIf="checkpoint['end_to_end_duration'] >= 0">
              {{ checkpoint['end_to_end_duration'] | humanizeDuration }}
            </td>
            <td *ngIf="checkpoint['end_to_end_duration'] < 0">n/a</td>
            <td>{{ checkpoint['checkpointed_size'] | humanizeBytes }}</td>
            <td>{{ checkpoint['state_size'] | humanizeBytes }}</td>
            <td>
              {{ checkpoint['processed_data'] | humanizeBytes }} ({{
                checkpoint['persisted_data'] | humanizeBytes
              }})
            </td>
          </tr>
          <tr [nzExpand]="checkpoint.expand">
            <td colspan="11" *ngIf="checkpoint.expand" class="collapse-td">
              <flink-job-checkpoints-detail
                [checkPoint]="checkpoint"
              ></flink-job-checkpoints-detail>
            </td>
          </tr>
        </ng-container>
      </tbody>
    </nz-table>
  </nz-tab>
  <nz-tab nzTitle="Summary">
    <nz-table
      *ngIf="checkPointStats"
      class="no-border small"
      [nzData]="checkPointStats && checkPointStats['summary'] ? [''] : []"
      [nzSize]="'small'"
      [nzFrontPagination]="false"
      [nzShowPagination]="false"
    >
      <thead>
        <tr>
          <th></th>
          <th><strong>End to End Duration</strong></th>
          <th>
            <strong>
              Checkpointed Data Size
              <i
                class="header-icon"
                nz-icon
                nz-tooltip
                nzTooltipTitle="The size of data persisted during the sync and async phases of a checkpoint. It's usually smaller than Full checkpoint data size if incremental checkpoints or changelog is enabled"
                nzType="info-circle"
              ></i>
            </strong>
          </th>
          <th><strong>Full Checkpoint Data Size</strong></th>
          <th><strong>Processed (persisted) in-flight data</strong></th>
        </tr>
      </thead>
      <tbody>
        <ng-container *ngIf="checkPointStats['summary']">
          <tr>
            <td><strong>Minimum</strong></td>
            <td>
              {{ checkPointStats['summary']['end_to_end_duration']?.min | humanizeDuration }}
            </td>
            <td>
              {{ checkPointStats['summary']['checkpointed_size']?.min | humanizeBytes }}
            </td>
            <td>{{ checkPointStats['summary']['state_size']?.min | humanizeBytes }}</td>
            <td>
              {{ checkPointStats['summary']['processed_data']?.min | humanizeBytes }} ({{
                checkPointStats['summary']['persisted_data']?.min | humanizeBytes
              }})
            </td>
          </tr>
          <tr>
            <td><strong>Average</strong></td>
            <td>
              {{ checkPointStats['summary']['end_to_end_duration']?.avg | humanizeDuration }}
            </td>
            <td>
              {{ checkPointStats['summary']['checkpointed_size']?.avg | humanizeBytes }}
            </td>
            <td>{{ checkPointStats['summary']['state_size']?.avg | humanizeBytes }}</td>
            <td>
              {{ checkPointStats['summary']['processed_data']?.avg | humanizeBytes }} ({{
                checkPointStats['summary']['persisted_data']?.avg | humanizeBytes
              }})
            </td>
          </tr>
          <tr>
            <td><strong>Maximum</strong></td>
            <td>
              {{ checkPointStats['summary']['end_to_end_duration']?.max | humanizeDuration }}
            </td>
            <td>
              {{ checkPointStats['summary']['checkpointed_size']?.max | humanizeBytes }}
            </td>
            <td>{{ checkPointStats['summary']['state_size']?.max | humanizeBytes }}</td>
            <td>
              {{ checkPointStats['summary']['processed_data']?.max | humanizeBytes }} ({{
                checkPointStats['summary']['persisted_data']?.max | humanizeBytes
              }})
            </td>
          </tr>
        </ng-container>
      </tbody>
    </nz-table>

    <nz-collapse>
      <nz-collapse-panel
        [nzHeader]="'Percentiles'"
        [nzActive]="moreDetailsPanel.active"
        [nzDisabled]="moreDetailsPanel.disabled"
      >
        <nz-table
          *ngIf="checkPointStats"
          class="no-border small"
          [nzData]="checkPointStats && checkPointStats['summary'] ? [''] : []"
          [nzSize]="'small'"
          [nzFrontPagination]="false"
          [nzShowPagination]="false"
        >
          <thead>
            <tr>
              <th></th>
              <th><strong>End to End Duration</strong></th>
              <th><strong>Checkpointed Data Size</strong></th>
              <th><strong>Full Checkpoint Data Size</strong></th>
              <th><strong>Processed (persisted) in-flight data</strong></th>
            </tr>
          </thead>
          <tbody>
            <ng-container *ngIf="checkPointStats['summary']">
              <tr>
                <td><strong>50% percentile</strong></td>
                <td>
                  {{ checkPointStats['summary']['end_to_end_duration']?.p50 | humanizeDuration }}
                </td>
                <td>
                  {{ checkPointStats['summary']['checkpointed_size']?.p50 | humanizeBytes }}
                </td>
                <td>{{ checkPointStats['summary']['state_size']?.p50 | humanizeBytes }}</td>
                <td>
                  {{ checkPointStats['summary']['processed_data']?.p50 | humanizeBytes }} ({{
                    checkPointStats['summary']['persisted_data']?.p50 | humanizeBytes
                  }})
                </td>
              </tr>
              <tr>
                <td><strong>90% percentile</strong></td>
                <td>
                  {{ checkPointStats['summary']['end_to_end_duration']?.p90 | humanizeDuration }}
                </td>
                <td>
                  {{ checkPointStats['summary']['checkpointed_size']?.p90 | humanizeBytes }}
                </td>
                <td>{{ checkPointStats['summary']['state_size']?.p90 | humanizeBytes }}</td>
                <td>
                  {{ checkPointStats['summary']['processed_data']?.p90 | humanizeBytes }} ({{
                    checkPointStats['summary']['persisted_data']?.p90 | humanizeBytes
                  }})
                </td>
              </tr>
              <tr>
                <td><strong>99% percentile</strong></td>
                <td>
                  {{ checkPointStats['summary']['end_to_end_duration']?.p99 | humanizeDuration }}
                </td>
                <td>
                  {{ checkPointStats['summary']['checkpointed_size']?.p99 | humanizeBytes }}
                </td>
                <td>{{ checkPointStats['summary']['state_size']?.p99 | humanizeBytes }}</td>
                <td>
                  {{ checkPointStats['summary']['processed_data']?.p99 | humanizeBytes }} ({{
                    checkPointStats['summary']['persisted_data']?.p99 | humanizeBytes
                  }})
                </td>
              </tr>
              <tr>
                <td><strong>99.9% percentile</strong></td>
                <td>
                  {{ checkPointStats['summary']['end_to_end_duration']?.p999 | humanizeDuration }}
                </td>
                <td>
                  {{ checkPointStats['summary']['checkpointed_size']?.p999 | humanizeBytes }}
                </td>
                <td>{{ checkPointStats['summary']['state_size']?.p999 | humanizeBytes }}</td>
                <td>
                  {{ checkPointStats['summary']['processed_data']?.p999 | humanizeBytes }} ({{
                    checkPointStats['summary']['persisted_data']?.p999 | humanizeBytes
                  }})
                </td>
              </tr>
            </ng-container>
          </tbody>
        </nz-table>
      </nz-collapse-panel>
    </nz-collapse>
  </nz-tab>
  <nz-tab nzTitle="Configuration">
    <nz-table
      class="no-border small"
      [nzData]="checkPointConfig ? [''] : []"
      [nzSize]="'small'"
      [nzFrontPagination]="false"
      [nzShowPagination]="false"
    >
      <thead>
        <tr>
          <th><strong>Option</strong></th>
          <th><strong>Value</strong></th>
        </tr>
      </thead>
      <tbody>
        <ng-container *ngIf="checkPointConfig">
          <tr>
            <td>Checkpointing Mode</td>
            <td *ngIf="checkPointConfig['mode'] === 'exactly_once'">Exactly Once</td>
            <td *ngIf="checkPointConfig['mode'] !== 'exactly_once'">At Least Once</td>
          </tr>
          <tr>
            <td>Checkpoint Storage</td>
            <td>{{ checkPointConfig['checkpoint_storage'] }}</td>
          </tr>
          <tr>
            <td>State Backend</td>
            <td>{{ checkPointConfig['state_backend'] }}</td>
          </tr>
          <tr>
            <td>Interval</td>
            <td *ngIf="checkPointConfig['interval'] === disabledInterval">
              Periodic checkpoints disabled
            </td>
            <td *ngIf="checkPointConfig['interval'] !== disabledInterval">
              {{ checkPointConfig['interval'] | humanizeDuration }}
            </td>
          </tr>
          <tr>
            <td>Timeout</td>
            <td>{{ checkPointConfig['timeout'] | humanizeDuration }}</td>
          </tr>
          <tr>
            <td>Minimum Pause Between Checkpoints</td>
            <td>{{ checkPointConfig['min_pause'] | humanizeDuration }}</td>
          </tr>
          <tr>
            <td>Maximum Concurrent Checkpoints</td>
            <td>{{ checkPointConfig['max_concurrent'] }}</td>
          </tr>
          <tr>
            <td>Unaligned Checkpoints</td>
            <td>{{ checkPointConfig['unaligned_checkpoints'] ? 'Enabled' : 'Disabled' }}</td>
          </tr>
          <tr *ngIf="checkPointConfig['unaligned_checkpoints']">
            <td>Aligned checkpoint timeout</td>
            <td>{{ checkPointConfig['aligned_checkpoint_timeout'] | humanizeDuration }}</td>
          </tr>
          <tr *ngIf="checkPointConfig['externalization']">
            <td>Persist Checkpoints Externally</td>
            <td *ngIf="checkPointConfig['externalization']['enabled']">
              Enabled
              <span *ngIf="checkPointConfig['externalization']['delete_on_cancellation']">
                (delete on cancellation)
              </span>
              <span *ngIf="!checkPointConfig['externalization']['delete_on_cancellation']">
                (retain on cancellation)
              </span>
            </td>
            <td *ngIf="!checkPointConfig['externalization']['enabled']">Disabled</td>
          </tr>
          <tr>
            <td>Tolerable Failed Checkpoints</td>
            <td>{{ checkPointConfig['tolerable_failed_checkpoints'] }}</td>
          </tr>
          <tr>
            <td>Checkpoints With Finished Tasks</td>
            <td>
              {{ checkPointConfig['checkpoints_after_tasks_finish'] ? 'Enabled' : 'Disabled' }}
            </td>
          </tr>
          <tr>
            <td>State Changelog</td>
            <td *ngIf="checkPointConfig['state_changelog_enabled']">Enabled</td>
            <td *ngIf="!checkPointConfig['state_changelog_enabled']">Disabled</td>
          </tr>
          <tr *ngIf="checkPointConfig['state_changelog_enabled']">
            <td>Changelog Storage</td>
            <td>{{ checkPointConfig['changelog_storage'] }}</td>
          </tr>
          <tr *ngIf="checkPointConfig['state_changelog_enabled']">
            <td>Changelog Periodic Materialization Interval</td>
            <td>
              {{
                checkPointConfig['changelog_periodic_materialization_interval'] | humanizeDuration
              }}
            </td>
          </tr>
        </ng-container>
      </tbody>
    </nz-table>
  </nz-tab>
</nz-tabset>

<ng-template #extraTemplate>
  <button nz-button nzType="primary" class="refresh" nzSize="small" (click)="refresh()">
    <i nz-icon nzType="sync"></i>
    Refresh
  </button>
</ng-template>

<nz-empty *ngIf="!checkPointStats"></nz-empty>
