package weed_server

import (
	"context"
	"encoding/json"
	"net/http"
	"strings"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/volume_server_pb"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
	"github.com/chrislusf/seaweedfs/weed/util"
)

func (vs *VolumeServer) FileGet(req *volume_server_pb.FileGetRequest, stream volume_server_pb.VolumeServer_FileGetServer) error {

	headResponse := &volume_server_pb.FileGetResponse{}
	n := new(needle.Needle)

	commaIndex := strings.LastIndex(req.FileId, ",")
	vid := req.FileId[:commaIndex]
	fid := req.FileId[commaIndex+1:]

	volumeId, err := needle.NewVolumeId(vid)
	if err != nil {
		headResponse.ErrorCode = http.StatusBadRequest
		return stream.Send(headResponse)
	}
	err = n.ParsePath(fid)
	if err != nil {
		headResponse.ErrorCode = http.StatusBadRequest
		return stream.Send(headResponse)
	}

	hasVolume := vs.store.HasVolume(volumeId)
	_, hasEcVolume := vs.store.FindEcVolume(volumeId)

	if !hasVolume && !hasEcVolume {
		headResponse.ErrorCode = http.StatusMovedPermanently
		return stream.Send(headResponse)
	}

	cookie := n.Cookie
	var count int
	if hasVolume {
		count, err = vs.store.ReadVolumeNeedle(volumeId, n)
	} else if hasEcVolume {
		count, err = vs.store.ReadEcShardNeedle(context.Background(), volumeId, n)
	}

	if err != nil || count < 0 {
		headResponse.ErrorCode = http.StatusNotFound
		return stream.Send(headResponse)
	}
	if n.Cookie != cookie {
		headResponse.ErrorCode = http.StatusNotFound
		return stream.Send(headResponse)
	}

	if n.LastModified != 0 {
		headResponse.LastModified = n.LastModified
	}

	headResponse.Etag = n.Etag()

	if n.HasPairs() {
		pairMap := make(map[string]string)
		err = json.Unmarshal(n.Pairs, &pairMap)
		if err != nil {
			glog.V(0).Infoln("Unmarshal pairs error:", err)
		}
		headResponse.Headers = pairMap
	}

	/*
		// skip this, no redirection
		if vs.tryHandleChunkedFile(n, filename, w, r) {
			return
		}
	*/

	if n.NameSize > 0 {
		headResponse.Filename = string(n.Name)
	}
	mtype := ""
	if n.MimeSize > 0 {
		mt := string(n.Mime)
		if !strings.HasPrefix(mt, "application/octet-stream") {
			mtype = mt
		}
	}
	headResponse.ContentType = mtype

	headResponse.IsGzipped = n.IsGzipped()

	if n.IsGzipped() && req.AcceptGzip {
		if n.Data, err = util.UnGzipData(n.Data); err != nil {
			glog.V(0).Infof("ungzip %s error: %v", req.FileId, err)
		}
	}

	headResponse.ContentLength = uint32(len(n.Data))
	bytesToRead := len(n.Data)
	bytesRead := 0

	t := headResponse

	for bytesRead < bytesToRead {

		stopIndex := bytesRead + BufferSizeLimit
		if stopIndex > bytesToRead {
			stopIndex = bytesToRead
		}

		if t == nil {
			t = &volume_server_pb.FileGetResponse{}
		}
		t.Data = n.Data[bytesRead:stopIndex]

		err = stream.Send(t)
		t = nil
		if err != nil {
			return err
		}

		bytesRead = stopIndex
	}

	return nil
}
