package com.datarecovery.master.utils.xfile;

import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.DocumentsContract;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class XSAFFile extends BaseXFile {

    private final Context context;
    private final Uri documentUri;
    private final Uri pathUri;
    private final String path;

    public XSAFFile(Context context, Uri treeRoot, List<String> segments) {
        this.context = context;

        if (segments == null || segments.size() == 0) {
            this.pathUri = treeRoot;
        } else {
            StringBuilder stringBuilder = new StringBuilder(treeRoot.toString());
            stringBuilder.append("%3A");
            for (int i = 0; i < segments.size(); i++) {
                stringBuilder.append(Uri.encode(segments.get(i)));
                if (i != segments.size() - 1) {
                    stringBuilder.append("%2F");
                }
            }
            this.pathUri = Uri.parse(stringBuilder.toString());
        }
        StringBuilder pathBuilder = new StringBuilder(File.separator);
        for (String segment : treeRoot.getPathSegments()) {
            pathBuilder.append(segment).append(File.separator);
        }
        if (segments != null && segments.size() != 0) {
            for (String segment : segments) {
                pathBuilder.append(segment).append(File.separator);
            }
            pathBuilder.deleteCharAt(pathBuilder.length() - 1);
        }
        this.path = pathBuilder.toString();

        String documentId;
        if (DocumentsContract.isDocumentUri(context, pathUri)) {
            documentId = DocumentsContract.getDocumentId(pathUri);
        } else {
            documentId = DocumentsContract.getTreeDocumentId(pathUri);
        }
        this.documentUri = DocumentsContract.buildDocumentUriUsingTree(pathUri, documentId);
    }

    public XSAFFile(Context context, Uri documentUri) {
        this.context = context;
        this.documentUri = documentUri;

        Uri treeRootUri = DocumentsContract.buildTreeDocumentUri(documentUri.getAuthority(),
                DocumentsContract.getDocumentId(documentUri));
        StringBuilder pathBuilder = new StringBuilder(File.separator);
        List<String> pathSegments = treeRootUri.getPathSegments();
        if (pathSegments != null && pathSegments.size() > 0) {
            for (String segment : pathSegments) {
                pathBuilder.append(segment).append(File.separator);
            }
            pathBuilder.deleteCharAt(pathBuilder.length() - 1);
        }
        this.path = pathBuilder.toString();
        this.pathUri = treeRootUri;
    }

    @Override
    public String getName() throws Exception {
        return queryForString(DocumentsContract.Document.COLUMN_DISPLAY_NAME);
    }

    @Override
    public String getPath() {
        return path;
    }

    @Override
    public Uri getUri() throws Exception {
        return documentUri;
    }

    @Override
    public boolean isDirectory() throws Exception {
        String mimeType = queryForString(DocumentsContract.Document.COLUMN_MIME_TYPE);
        return Objects.equals(mimeType, DocumentsContract.Document.MIME_TYPE_DIR);
    }

    @Override
    public XFile[] listFiles() {
        Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(documentUri, DocumentsContract.getDocumentId(documentUri));
        try (Cursor cursor = context.getContentResolver().query(childrenUri, new String[]{DocumentsContract.Document.COLUMN_DOCUMENT_ID},
                null, null, null)) {
            ArrayList<XFile> children = new ArrayList<>();
            if (cursor != null && cursor.moveToFirst()) {
                do {
                    String documentId = cursor.getString(0);
                    Uri childUri = DocumentsContract.buildDocumentUriUsingTree(documentUri, documentId);
                    children.add(new XSAFFile(context, childUri));
                } while (cursor.moveToNext());
            }
            return children.toArray(new XFile[0]);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public boolean exists() throws Exception {
        return queryForString(DocumentsContract.Document.COLUMN_DOCUMENT_ID) != null;
    }

    @Override
    public boolean delete() {
        try {
            DocumentsContract.deleteDocument(context.getContentResolver(), documentUri);
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public long length() throws Exception {
        return queryForLong(DocumentsContract.Document.COLUMN_SIZE);
    }

    @Override
    public long lastModified() throws Exception {
        return queryForLong(DocumentsContract.Document.COLUMN_LAST_MODIFIED);
    }

    @Override
    public InputStream newInputStream() throws Exception {
        return context.getContentResolver().openInputStream(documentUri);
    }

    public Uri getPathUri() {
        return pathUri;
    }

    public Uri getDocumentUri() {
        return documentUri;
    }

    private String queryForString(String colum) throws Exception {
        try (Cursor cursor = context.getContentResolver().query(documentUri, new String[]{colum},
                null, null, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                return cursor.getString(0);
            }
        }
        return null;
    }

    private long queryForLong(String colum) throws Exception {
        try (Cursor cursor = context.getContentResolver().query(documentUri, new String[]{colum},
                null, null, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                return cursor.getLong(0);
            }
        }
        return 0;
    }
}