/*
 * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. 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.
 */

import React, {Component} from 'react';
import '../App.css';
import Subheader from 'material-ui/Subheader';
import {Card, CardMedia} from 'material-ui/Card';
import FlatButton from 'material-ui/FlatButton';
import Avatar from 'material-ui/Avatar';
import List from 'material-ui/List/List';
import ListItem from 'material-ui/List/ListItem';
import Divider from 'material-ui/Divider';
import AceEditor from 'react-ace';
import LinearProgress from 'material-ui/LinearProgress';
import CircularProgress from 'material-ui/CircularProgress';
import {
  Table,
  TableBody,
  TableHeader,
  TableHeaderColumn,
  TableRow,
  TableRowColumn,
} from 'material-ui/Table';
import Download from 'downloadjs'
import Websocket from 'react-websocket';
import Snackbar from 'material-ui/Snackbar';

/**
 * View responsible for displaying test run log and summary information.
 *
 * @since 1.0.0
 */
class TestRunView extends Component {

  constructor(props) {
    super(props);
    this.baseURL = "/testgrid/dashboard";
    this.state = {
      testScenarioSummaries: [],
      scenarioTestCaseEntries: [],
      testSummaryLoadStatus: "PENDING",
      logContent: "",
      logDownloadStatus: "PENDING",
      isLogTruncated: false,
      inputStreamSize: "",
      showLogDownloadErrorDialog: false
    };
  }

  componentDidMount() {
    const testScenarioSummaryUrl = this.baseURL + '/api/test-plans/test-summary/' +
      this.props.active.reducer.currentInfra.testPlanId;
    const logTruncatedContentUrl = this.baseURL + '/api/test-plans/log/' +
      this.props.active.reducer.currentInfra.testPlanId + "?truncate=" + true;

    fetch(testScenarioSummaryUrl, {
      method: "GET",
      headers: {
        'Accept': 'application/json'
      }
    }).then(response => {
      this.setState({
        testSummaryLoadStatus: response.ok ? "SUCCESS" : "ERROR"
      });
      return response.json();
    }).then(data => this.setState({
      testScenarioSummaries: data.scenarioSummaries,
      scenarioTestCaseEntries: data.scenarioTestCaseEntries
    }));

    if (this.props.active.reducer.currentInfra.testPlanStatus === "FAILS" ||
      this.props.active.reducer.currentInfra.testPlanStatus === "SUCCESS") {
      fetch(logTruncatedContentUrl, {
        method: "GET",
        headers: {
          'Accept': 'application/json'
        }
      }).then(response => {
        this.setState({
          logDownloadStatus: response.ok ? "SUCCESS" : "ERROR"
        });
        return response.json();
      }).then(data =>
        this.setState({
          logContent: data.inputStreamContent,
          isLogTruncated: data.truncated,
          inputStreamSize: data.completeInputStreamSize
        }));
    }
  }

  handleLogDownloadErrorDialogClose = () => {
    this.setState({
      showLogDownloadErrorDialog: false,
    });
  };

  handleLiveLogData(data) {
    this.setState({logContent: this.state.logContent + data});
  }

  render() {
    const subHeader = (<td style={{padding: 5}}>
      <i> {this.props.active.reducer.currentProduct.productName}
        {this.props.active.reducer.currentProduct.productVersion}
        {this.props.active.reducer.currentProduct.productChannel} /
        {this.props.active.reducer.currentDeployment.deploymentPatternName} /
        {this.props.active.reducer.currentInfra.infraParameters}</i>
    </td>);
    const divider = (<Divider inset={false} style={{borderBottomWidth: 1}}/>);
    const logAllContentUrl = this.baseURL + '/api/test-plans/log/' +
      this.props.active.reducer.currentInfra.testPlanId + "?truncate=" + false;
    let isFailedTestsTitleAdded = false;

    return (
      <div>
        {/*Sub header*/}
        {(() => {
          switch (this.props.active.reducer.currentInfra.testPlanStatus) {
            case "FAIL":
              return <Subheader style={{
                fontSize: '20px',
                backgroundColor: "#ffd6d3"
              }}>
                <table>
                  <tbody>
                  <tr>
                    <td style={{padding: 5}}>
                      <img
                        src={require('../close.png')}
                        style={{
                          verticalAlign: "middle",
                          height: "50px",
                          width: "50px"
                        }}/>
                    </td>
                    {subHeader}
                  </tr>
                  </tbody>
                </table>
              </Subheader>;
            case "SUCCESS":
              return <Subheader style={{
                fontSize: '20px',
                backgroundColor: "#cdffba"
              }}>
                <table>
                  <tbody>
                  <tr>
                    <td style={{padding: 5}}>
                      <img
                        src={require('../success.png')}
                        style={{
                          verticalAlign: "middle",
                          height: "50px",
                          width: "50px"
                        }}/>
                    </td>
                    {subHeader}
                  </tr>
                  </tbody>
                </table>
              </Subheader>;
            case "PENDING":
            case "RUNNING":
            default:
              return <Subheader style={{
                fontSize: '20px',
                backgroundColor: "#d7d9ff"
              }}>
                <table>
                  <tbody>
                  <tr>
                    <td style={{padding: 5}}>
                      <CircularProgress size={80} thickness={8}/>
                    </td>
                    {subHeader}
                  </tr>
                  </tbody>
                </table>
              </Subheader>;
          }
        })()}
        <Card style={{padding: 20}}>
          <CardMedia>
            {/*TestGrid generated contents*/}
            <List>
              <ListItem disabled={true}
                        leftAvatar={
                          <Avatar
                            src={require('../log.png')}
                            size={50}
                            style={{
                              borderRadius: 0,
                              backgroundColor: "#ffffff"
                            }}/>
                        }>
                <FlatButton label="Download Test Run Log"
                            onClick={() => (fetch(logAllContentUrl, {
                              method: "GET",
                              headers: {
                                'Accept': 'application/json'
                              }
                            }).then(response => {
                              this.setState({
                                showLogDownloadErrorDialog: !response.ok
                              });
                              return response.json();
                            }).then(data => {
                                if (!this.state.showLogDownloadErrorDialog) {
                                  Download(data.inputStreamContent, "test-run.log", "plain/text");
                                }
                              }
                            ))}
                />
                <Snackbar
                  open={this.state.showLogDownloadErrorDialog}
                  message="Error on downloading log file..."
                  autoHideDuration={4000}
                  onRequestClose={this.handleLogDownloadErrorDialogClose}
                  contentStyle={{
                    fontWeight: 600,
                    fontSize: "15px"
                  }}
                />
              </ListItem>
            </List>
            {divider}
            {/*Scenario execution summary*/}
            <h2>Scenario execution summary</h2>
            {(() => {
              switch (this.state.testSummaryLoadStatus) {
                case "ERROR":
                  return <div style={{
                    padding: 5,
                    color: "#D8000C",
                    backgroundColor: "#FFD2D2"
                  }}>
                    <br/>
                    <strong>Oh snap! </strong>
                    Error occurred when loading test summaries.
                  </div>;
                case "SUCCESS":
                  return <div>
                    <Table>
                      <TableHeader displaySelectAll={false}
                                   adjustForCheckbox={false}>
                        <TableRow>
                          <TableHeaderColumn
                            style={{width: "5%", textAlign: "center"}}/>
                          <TableHeaderColumn>
                            <h2>Scenario</h2>
                          </TableHeaderColumn>
                          <TableHeaderColumn
                            style={{width: "15%", textAlign: "center"}}>
                            <h2>Total Success</h2>
                          </TableHeaderColumn>
                          <TableHeaderColumn
                            style={{width: "15%", textAlign: "center"}}>
                            <h2>Total Failed</h2>
                          </TableHeaderColumn>
                          <TableHeaderColumn
                            style={{width: "15%", textAlign: "center"}}>
                            <h2>Success Percentage</h2>
                          </TableHeaderColumn>
                        </TableRow>
                      </TableHeader>
                      <TableBody displayRowCheckbox={false}
                                 showRowHover={true}>
                        {this.state.testScenarioSummaries.map((data, index) => {
                          return (<TableRow key={index}>
                            <TableRowColumn style={{width: "5%"}}>
                              {(() => {
                                switch (data.scenarioStatus) {
                                  case "SUCCESS":
                                    return <div>
                                      <img width="36"
                                           height="36"
                                           src={require('../success.png')}/>
                                    </div>;
                                  case "FAIL":
                                    return <div>
                                      <img width="36"
                                           height="36"
                                           src={require('../close.png')}/>
                                    </div>;
                                  case "PENDING":
                                  case "RUNNING":
                                  default:
                                    return <div>
                                      <CircularProgress
                                        size={40}
                                        thickness={8}/>
                                    </div>
                                }
                              })()}
                            </TableRowColumn>
                            <TableRowColumn style={{
                              fontSize: "15px",
                              wordWrap: "break-word",
                              whiteSpace: "wrap"
                            }}>{data.scenarioName}</TableRowColumn>
                            <TableRowColumn
                              style={{
                                width: "15%",
                                textAlign: "center",
                                color: "#189800",
                                fontSize: "20px",
                                wordWrap: "break-word",
                                whiteSpace: "wrap"
                              }}>{data.totalSuccess}</TableRowColumn>
                            <TableRowColumn
                              style={{
                                width: "15%",
                                textAlign: "center",
                                color: "#c12f29",
                                fontSize: "20px",
                                wordWrap: "break-word",
                                whiteSpace: "wrap"
                              }}>{data.totalFail}</TableRowColumn>
                            <TableRowColumn
                              style={{
                                width: "15%",
                                textAlign: "center",
                                fontSize: "20px",
                                wordWrap: "break-word",
                                whiteSpace: "wrap"
                              }}>
                              {
                                isNaN(data.successPercentage) ?
                                  "0.0" :
                                  parseFloat(data.successPercentage).toFixed(2)
                              }%
                            </TableRowColumn>
                          </TableRow>)
                        })}
                      </TableBody>
                    </Table>
                    <br/>
                    <br/>
                    {divider}
                    {/*Detailed Report for failed test cases*/}
                    {this.state.scenarioTestCaseEntries.map((data, index) => {
                      if (data.testCaseEntries.length > 0) {
                        const failedTestTitleContent = isFailedTestsTitleAdded ?
                          "" : <h2>Failed Tests</h2>;
                        isFailedTestsTitleAdded = true;
                        return (
                          <div>
                            {failedTestTitleContent}
                            <h2 style={{
                              color: "#e46226"
                            }}>{data.scenarioName}</h2>
                            <Table>
                              <TableHeader displaySelectAll={false}
                                           adjustForCheckbox={false}>
                                <TableRow>
                                  <TableHeaderColumn
                                    style={{
                                      width: "5%",
                                      textAlign: "center"
                                    }}/>
                                  <TableHeaderColumn
                                    style={{
                                      width: "30%"
                                    }}>
                                    <h2>Test Case</h2>
                                  </TableHeaderColumn>
                                  <TableHeaderColumn
                                    style={{
                                      width: "65%"
                                    }}>
                                    <h2>Failure Message</h2>
                                  </TableHeaderColumn>
                                </TableRow>
                              </TableHeader>
                              <TableBody displayRowCheckbox={false}
                                         showRowHover={true}>
                                {data.testCaseEntries.map((entry, index) => {
                                  return (
                                    <TableRow key={index}>
                                      <TableRowColumn
                                        style={{width: "5%"}}>
                                        {entry.isTestSuccess ?
                                          <img width="36"
                                               height="36"
                                               src={require('../success.png')}/>
                                          :
                                          <img width="36"
                                               height="36"
                                               src={require('../close.png')}/>}
                                      </TableRowColumn>
                                      <TableRowColumn style={{
                                        fontSize: "15px",
                                        width: "30%",
                                        wordWrap: "break-word",
                                        whiteSpace: "wrap",
                                      }}>{entry.testCase}</TableRowColumn>
                                      <TableRowColumn style={{
                                        fontSize: "15px",
                                        width: "65%",
                                        wordWrap: "break-word",
                                        whiteSpace: "wrap",
                                        paddingTop: 15,
                                        paddingBottom: 15
                                      }}>
                                        {entry.failureMessage}
                                      </TableRowColumn>
                                    </TableRow>
                                  )
                                })}
                              </TableBody>
                            </Table>
                            <br/>
                          </div>)
                      } else {
                        return ("")
                      }
                    })}
                  </div>;
                case "PENDING":
                default:
                  return <div>
                    <br/>
                    <br/>
                    <b>Loading test summaries...</b>
                    <br/>
                    <LinearProgress mode="indeterminate"/>
                  </div>;
              }
            })()}
            {divider}
            <br/>
            {/*Test log*/}
            <h2>Test Run Log</h2>
            {/*Display log from file system*/}
            {(() => {
              switch (this.props.active.reducer.currentInfra.testPlanStatus) {
                case "PENDING":
                case "RUNNING":
                  return (<div>
                    <Websocket
                      url={'wss://' + window.location.hostname + this.baseURL + '/live-log/' +
                      this.props.active.reducer.currentInfra.testPlanId}
                      onMessage={data => {
                        this.handleLiveLogData(data)
                      }}/>
                    <AceEditor
                      theme="github"
                      ref="log"
                      fontSize={16}
                      showGutter={true}
                      highlightActiveLine={true}
                      value={this.state.logContent}
                      wrapEnabled={true}
                      readOnly={true}
                      setOptions={{
                        showLineNumbers: true,
                        maxLines: Infinity
                      }}
                      style={{
                        width: this.props.containerWidth
                      }}/>
                    <center><CircularProgress size={40} thickness={8}/></center>
                  </div>);
                case "FAIL":
                case "SUCCESS":
                default: {
                  // Display Log from S3
                  switch (this.state.logDownloadStatus) {
                    case "ERROR":
                      return <div style={{
                        padding: 5,
                        color: "#D8000C",
                        backgroundColor: "#FFD2D2"
                      }}>
                        <br/>
                        <strong>Oh snap! </strong>
                        Error occurred when downloading the log file content.
                      </div>;
                    case "SUCCESS":
                      return <div>
                        <AceEditor
                          theme="github"
                          ref="log"
                          fontSize={16}
                          showGutter={true}
                          highlightActiveLine={true}
                          value={this.state.logContent}
                          wrapEnabled={true}
                          readOnly={true}
                          setOptions={{
                            showLineNumbers: true,
                            maxLines: Infinity
                          }}
                          style={{
                            width: this.props.containerWidth
                          }}/>
                        {this.state.isLogTruncated ?
                          <div>
                            <center>
                              <FlatButton
                                onClick={() => (fetch(logAllContentUrl, {
                                  method: "GET",
                                  headers: {
                                    'Accept': 'application/json'
                                  }
                                }).then(response => {
                                  this.setState({
                                    logDownloadStatus: response.ok ? "SUCCESS" : "ERROR"
                                  });
                                  return response;
                                }).then(data => data.json().then(json =>
                                  this.setState({
                                    logContent: json.inputStreamContent,
                                    isLogTruncated: false
                                  }),
                                )))}
                                label={"See More (" + this.state.inputStreamSize + ")"}
                                labelStyle={{
                                  fontSize: '20px',
                                  fontWeight: 600
                                }}
                                style={{
                                  color: '#0E457C'
                                }}/>
                            </center>
                          </div>
                          : ""}
                      </div>;
                    case "PENDING":
                    default:
                      return <div>
                        <br/>
                        <br/>
                        <b>Loading test log...</b>
                        <br/>
                        <LinearProgress mode="indeterminate"/>
                      </div>;
                  }
                }
              }
            })()}
          </CardMedia>
          <br/>
          <br/>
        </Card>
      </div>
    );
  }
}

export default TestRunView;
