package com.oakzmm.demoapp.network;


import android.content.Context;
import android.util.Log;

import com.google.gson.Gson;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.List;
import java.util.concurrent.TimeUnit;

import okio.Buffer;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;

import static android.content.ContentValues.TAG;


/**
 * PatrolDev
 * Created by acer_april
 * on 2016/3/14
 * Description:
 * <p/>
 * 用法同HttpClientRequest,
 * 注意
 * 1.callback 的回调非UI线程;
 * 2.需要自己解析Response数据,暂不支持解析为JavaBean,解析方法  new Gson().fromJson( response.body().string(),Bean.class);
 */
public class UploadFileRequest {

    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
    private static Context mContext;
    public OkHttpClient mOkHttpClient;
//    public Call call;
//    private String url = RequestConstant.UPLOAD_FILE;

    private UploadFileRequest() {
        mOkHttpClient = new OkHttpClient();
    }

    public static UploadFileRequest getInstance(Context context) {
        // it keeps you from leaking the Activity or BroadcastReceiver if someone passes one in.
        mContext = context.getApplicationContext();
        return ClientHolder.CLIENT_REQUEST;
    }

    public static RequestBody createCustomRequestBody(final MediaType contentType, final File file, final UploadCallback listener) {
        return new RequestBody() {
            @Override
            public MediaType contentType() {
                return contentType;
            }

            @Override
            public long contentLength() {
                return file.length();
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                Source source;
                try {
                    source = Okio.source(file);
                    //sink.writeAll(source);
                    Buffer buf = new Buffer();
                    Long remaining = contentLength();
                    for (long readCount; (readCount = source.read(buf, 2048)) != -1; ) {
                        sink.write(buf, readCount);
                        listener.onProgress(contentLength(), remaining -= readCount, remaining == 0);

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }

    private OkHttpClient getOkHttpClient() {
        return mOkHttpClient;
    }


    /**
     * 上传单个文件
     *
     * @param url      upload url
     * @param clazz    upload params
     * @param file     upload file
     * @param callback callback
     */
    public void uploadFile(String url, Object clazz, File file, UploadCallback callback) {
        final MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);
        // add params
        String json = new Gson().toJson(clazz);
        builder.addFormDataPart(RequestConstant.UPLOAD_KEY_JSON, json);
        // add file
        if (file != null) {
            final MediaType type = MediaType.parse(guessMimeType(file.getName()));
            final RequestBody body = createCustomRequestBody(type, file, callback);
            builder.addFormDataPart(RequestConstant.UPLOAD_KEY_FILE, file.getName(), body);
        }
        RequestBody requestBody = builder.build();

        newRequestCall(callback, url, requestBody);
    }

    /**
     * 上传多个文件
     *
     * @param url      upload url
     * @param clazz    upload params
     * @param files    upload files
     * @param callback callback
     */
    public void uploadFiles(String url, Object clazz, List<File> files, UploadCallback callback) {
        newRequestCall(callback, url, buildRequestBody(clazz, files, callback));
    }

    /**
     * 下载文件
     *
     * @param fileUrl download url
     * @param file save file
     * @param callback callback
     */
    public void downloadFile(String fileUrl, final File file, final DownloadCallback callback) {
        if (file.exists()) {
            callback.onProgress(1, 1, true);
            return;
        }
        final Request request = new Request.Builder().url(fileUrl).build();
        final Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {

            }

            @Override
            public void onResponse(Response response) throws IOException {
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                try {
                    long total = response.body().contentLength();
                    long current = 0;
                    is = response.body().byteStream();
                    fos = new FileOutputStream(file);
                    while ((len = is.read(buf)) != -1) {
                        current += len;
                        fos.write(buf, 0, len);
                        callback.onProgress(total, current, current == total);
                    }
                    fos.flush();
                } catch (IOException e) {
                    Log.e(TAG, e.toString());
                } finally {
                    try {
                        if (is != null) {
                            is.close();
                        }
                        if (fos != null) {
                            fos.close();
                        }
                    } catch (IOException e) {
                        Log.e(TAG, e.toString());
                    }
                }
            }


        });
    }

    private void newRequestCall(Callback callback, String url, RequestBody requestBody) {
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(callback);
    }

    protected RequestBody buildRequestBody(Object clazz, List<File> files, UploadCallback callback) {
        MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);
        String json = new Gson().toJson(clazz);
        // add params
        builder.addFormDataPart(RequestConstant.UPLOAD_KEY_JSON, json);
        //add file
        if (files != null) {
            int count = files.size();
            for (int i = 0; i < count; i++) {
                File fileInput = files.get(i);
                final MediaType type = MediaType.parse(guessMimeType(fileInput.getName()));
                final RequestBody fileBody = createCustomRequestBody(type, fileInput, callback);
                builder.addFormDataPart(RequestConstant.UPLOAD_KEY_FILE, fileInput.getName(), fileBody);
            }
        }
        return builder.build();
    }

    public void setConnectTimeout(int timeout, TimeUnit units) {
        getOkHttpClient().setConnectTimeout(timeout, units);
    }

    public void setReadTimeout(int timeout, TimeUnit units) {
        getOkHttpClient().setReadTimeout(timeout, units);
    }

    public void setWriteTimeout(int timeout, TimeUnit units) {
        getOkHttpClient().setWriteTimeout(timeout, units);
    }

//    public void cancelCall() {
//        if (call != null)
//            call.cancel();
//    }

    private String guessMimeType(String path) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String contentTypeFor = fileNameMap.getContentTypeFor(path);
        if (contentTypeFor == null) {
            contentTypeFor = "application/octet-stream";
        }
        return contentTypeFor;
    }

    private static class ClientHolder {
        private static final UploadFileRequest CLIENT_REQUEST = new UploadFileRequest();
    }

}