package smb

import (
	"context"
	"os"
	"strings"

	"github.com/izouxv/logx"
	"imuslab.com/smb/driver/mod/smb/encoder"
)

func init() {
	commandRequestMap[CommandSetInfo] = func() DataI {
		return &SetInfoRequest{}
	}
}

type SetInfoRequest struct {
	Header
	StructureSize         uint16
	InfoType              InfoType
	FileInfoClass         FileInformationClass //https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/4718fc40-e539-4014-8e33-b675af74e3e1
	BufferLength          uint32               `smb:"len:Buffer"`
	BufferOffset          uint16               `smb:"offset:Buffer"`
	Reserved              uint16
	AdditionalInformation uint32
	FileId                GUID

	Buffer []byte
}

type SetInfoResponse struct {
	Header
	StructureSize uint16
}

func (data *SetInfoRequest) ServerAction(ctx *DataCtx) (interface{}, error) {
	data.Header.Flags = SMB2_FLAGS_RESPONSE

	// if !data.FileId.IsEqual(LastGUID) {
	// 	panic(-1)
	// }

	if data.InfoType != SMB2_0_INFO_FILE {
		logx.Warnf("data.InfoType NotSupport: %v", data.InfoType)
		return ERR(data.Header, STATUS_NOT_SUPPORTED)
	}
	if len(data.Buffer) > 0 {
		fileid := ctx.FileID(data.FileId)
		webfile, ok := ctx.session.openedFiles[fileid]
		if !ok {
			return ERR(data.Header, STATUS_FILE_CLOSED)
		}

		switch data.FileInfoClass {
		case FileBasicInformation:
			resp := &FileBasicInformationX{}
			if err := encoder.Unmarshal(data.Buffer, resp); err == nil {
				ctx.closeAction = func() {
				}
			}
		case FileDispositionInformation:
			resp := &FileDispositionInformationX{}
			if err := encoder.Unmarshal(data.Buffer, resp); err == nil {
				if file, ok := webfile.(*os.File); ok {
					//删除文件.
					if resp.DeletePending == 1 {
						ctx.closeAction = func() {
							FilePath := file.Name()
							ctx.Handle().FileSystem.RemoveAll(context.Background(), FilePath)
						}
					}
				}
				if file, ok := webfile.(*webdavFile); ok {
					//删除文件xattr属性
					ctx.closeAction = func() {
						file.XAttrDelete()
					}
				}
			}

		case FileRenameInformation:

			resp := &FileRenameInformationX{}
			if err := encoder.Unmarshal(data.Buffer, resp); err == nil {
				if file, ok := webfile.(*os.File); ok {
					FilePath := file.Name()
					// ctx.closeAction = func() {
					filename, err := encoder.FromUnicode(resp.FileName)
					if err != nil {
						return ERR(data.Header, STATUS_UNSUCCESSFUL)
					}
					filename = strings.ReplaceAll(filename, "\\", "/")
					NewFilePath := ctx.session.GetAbsPath(filename)
					if resp.ReplaceIfExists == 0x01 {
						err = ctx.Handle().FileSystem.RemoveAll(context.Background(), NewFilePath)
						if err != nil {
							return ERR(data.Header, STATUS_UNSUCCESSFUL)
						}
					}
					err = ctx.Handle().FileSystem.Rename(context.Background(), FilePath, NewFilePath)
					if err != nil {
						return ERR(data.Header, STATUS_UNSUCCESSFUL)
					}
					// }
				}
			}
		default:
			logx.Warnf("data.FileInfoClass NotSupport: %v", data.FileInfoClass)
			return ERR(data.Header, STATUS_NOT_SUPPORTED)
		}
	}

	data.Header.Status = StatusOk
	resp := SetInfoResponse{
		Header:        data.Header,
		StructureSize: 2,
	}
	return &resp, nil
}
