import React from 'react';
import { Link, useParams } from 'react-router-dom';
import { S3Client, ListObjectsV2Command, GetObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3';

import Alert from 'react-bootstrap/Alert';
import Breadcrumb from 'react-bootstrap/Breadcrumb';
import Button from 'react-bootstrap/Button';
import Container from 'react-bootstrap/Container';
import Card from 'react-bootstrap/Card';
import ListGroup from 'react-bootstrap/ListGroup';
import Stack from 'react-bootstrap/Stack';
import { LinkContainer } from 'react-router-bootstrap'

import ObjectInfo from './ObjectInfo';
import UploadFiles from './UploadFiles';
import downloadFile from './downloadFile';

import { BsInfoCircle, BsFolder, BsFileEarmarkText, BsDownload } from 'react-icons/bs';
import { AiOutlineDelete } from 'react-icons/ai';

type Props = {
  client: S3Client;
  bucket: string;
  prefix: string;
};

type State = {
  loaded: boolean;
  folders: string[];
  files: string[];
  info: string | null;
  iInfo: number;
  iUpload: number;
};

var cache: { [path: string]: State; } = {};

class ObjectList extends React.Component<Props, State> {
  state = {
    loaded: false,
    folders: [],
    files: [],
    info: null,
    iInfo: 0,
    iUpload: 0,
  };

  constructor(props: Props) {
    super(props);
  }

  componentDidMount() {
    //console.log(this.props);

    if (cache[this.path()]) {
      this.setState(cache[this.path()]);
    }

    this.loadEntries();
  }

  async loadEntries() {
    let command = new ListObjectsV2Command({
      Bucket: this.props.bucket,
      Prefix: this.props.prefix,
      Delimiter: '/',
    });
    try {
      const pxlen = this.props.prefix.length;

      const data = await this.props.client.send(command);
      //console.log("ok", data);

      const folders = (data.CommonPrefixes || []).map((cp) => cp.Prefix!.substring(pxlen));
      const files = (data.Contents || []).map((obj) => obj.Key!.substring(pxlen));

      folders.sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}));
      files.sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}));

      this.setState({
        loaded: true,
        folders: folders,
        files: files,
      });
      cache[this.path()] = this.state;
    } catch(error) {
      console.log("err", error);
    }
  }

  path() {
    return this.props.bucket + "/" + this.props.prefix;
  }

  renderBreadcrumbs() {
    let spl = this.props.prefix.split("/");
    let items = [];
    for (var i = 0; i < spl.length - 1; i++) {
      let to =  "/" + this.props.bucket + "/" + spl.slice(0, i+1).join("/") + "/" ;
      if (i < spl.length - 2) {
        items.push(
          <LinkContainer to={to} key={to}>
            <Breadcrumb.Item>{ spl[i] }</Breadcrumb.Item>
          </LinkContainer>
          );
      } else {
        items.push(
            <Breadcrumb.Item active key={to}>{ spl[i] }</Breadcrumb.Item>
          );
      }
    }
    return (
      <Breadcrumb>
        <LinkContainer key="BUCKETS" to="/">
          <Breadcrumb.Item>my buckets</Breadcrumb.Item>
        </LinkContainer>
        { this.props.prefix == "" ?
            <Breadcrumb.Item active>{ this.props.bucket }</Breadcrumb.Item>
          :
          <LinkContainer key="BUCKET" to={ "/" + this.props.bucket + "/" }>
            <Breadcrumb.Item>{ this.props.bucket }</Breadcrumb.Item>
          </LinkContainer>
        }
        { items }
      </Breadcrumb>
    );
  }

  openInfo(f: string) {
    this.setState({info: f, iInfo: this.state.iInfo + 1});
  }

  async deleteFile(f: string) {
    if (window.confirm("Really delete file " + f + "?")) {
      console.log("DELETING", f);
      let command = new DeleteObjectCommand({
        Bucket: this.props.bucket,
        Key: this.props.prefix + f,
      });
      let res = await this.props.client.send(command);
      this.loadEntries();
    }
  }

  openUpload() {
    this.setState({iUpload: this.state.iUpload + 1});
  }

  onUploadComplete() {
    this.loadEntries();
  }

  render() {
    if (!this.state.loaded) {
      return (
        <>
          { this.renderBreadcrumbs() }
          <Alert variant="secondary">Loading...</Alert>
        </>
        );
    }

    return (
      <>
        { this.state.iUpload > 0 ?
          <UploadFiles
            key={ "upload" + this.state.iUpload }
            client={this.props.client}
            bucket={this.props.bucket}
            prefix={this.props.prefix} 
            onUploadComplete={() => this.onUploadComplete()}
            />
          : <></> }
        { this.state.info ?
          <ObjectInfo
            key={ "info" + this.state.iInfo }
            client={ this.props.client }
            bucket={this.props.bucket}
            s3key={this.props.prefix + this.state.info}
            filename={this.state.info} />
          : <></> }
        <Container className="pb-3">
          <Stack direction="horizontal">
            <div className="mt-1">
              { this.renderBreadcrumbs() }
            </div>
            <div className="ms-auto">
              <Button size="sm" variant="info" onClick={(event) => this.openUpload()}>
                Upload files
              </Button>
            </div>
          </Stack>
        </Container>
        <ListGroup>
          { this.state.folders.map((f) =>
            <LinkContainer key={f + "/"} to={ "/" + this.props.bucket + "/" + this.props.prefix + f }>
              <ListGroup.Item action>
              <BsFolder /> { f }
              </ListGroup.Item>
            </LinkContainer>
          )}
          { this.state.files.map((f) =>
              <ListGroup.Item key={f}>
                <Stack direction="horizontal">
                  <div><BsFileEarmarkText /> { f }</div>
                  <div className="ms-auto">
                    <Button size="sm" className="mx-1" variant="primary" onClick={(event) => {
                      event.stopPropagation();
                      downloadFile(this.props.client, this.props.bucket, this.props.prefix + f, f);
                    }}>
                      <BsDownload />
                    </Button>
                    <Button size="sm" className="mx-1" variant="danger" onClick={(event) => {
                      event.stopPropagation();
                      this.deleteFile(f);
                    }}>
                      <AiOutlineDelete />
                    </Button>
                    <Button size="sm" className="mx-1" variant="secondary" onClick={(event) => {
                      event.stopPropagation();
                      this.openInfo(f);
                    }}>
                      <BsInfoCircle />
                    </Button>
                  </div>
                </Stack>
              </ListGroup.Item>
          )}
        </ListGroup>
      </>
    );
  }
}


function isBlob(obj: any): obj is Blob {
  return !! obj;
}


interface IClient {
  client: S3Client;
}

export const ObjectList1 = ({ client }: IClient) => {
  const params = useParams();
  const bucket = params["bucket"]!;
  return <>
    <ObjectList client={client} bucket={bucket} prefix="" key={bucket} />
   </>;
};

export const ObjectList2 = ({ client }: IClient) => {
  const params = useParams();
  const bucket = params["bucket"]!;
  const prefix = params["*"] || "";
  const key = bucket + "/" + prefix;
  return <>
    <ObjectList client={client} bucket={bucket} prefix={prefix} key={key} />
  </>;
};
