// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

//go:build windows
// +build windows

package protocol

// Windows uses backslashes as file separator

import (
	"log/slog"
	"path/filepath"
	"strings"

	"github.com/syncthing/syncthing/internal/slogutil"
)

func makeNative(m rawModel) rawModel { return nativeModel{m} }

type nativeModel struct {
	rawModel
}

func (m nativeModel) Index(idx *Index) error {
	idx.Files = fixupFiles(idx.Files)
	return m.rawModel.Index(idx)
}

func (m nativeModel) IndexUpdate(idxUp *IndexUpdate) error {
	idxUp.Files = fixupFiles(idxUp.Files)
	return m.rawModel.IndexUpdate(idxUp)
}

func (m nativeModel) Request(req *Request) (RequestResponse, error) {
	if strings.Contains(req.Name, `\`) {
		slog.Debug("Dropping request containing invalid path separator", slogutil.FilePath(req.Name))
		return nil, ErrNoSuchFile
	}

	req.Name = filepath.FromSlash(req.Name)
	return m.rawModel.Request(req)
}

func fixupFiles(files []FileInfo) []FileInfo {
	var out []FileInfo
	for i := range files {
		if strings.Contains(files[i].Name, `\`) {
			if files[i].Deleted {
				// Dropping a deleted item doesn't have any consequences.
				slog.Debug("Dropping index entry containing invalid path separator", slogutil.FilePath(files[i].Name))
			} else {
				slog.Error("Dropping index entry containing invalid path separator", slogutil.FilePath(files[i].Name))
			}
			if out == nil {
				// Most incoming updates won't contain anything invalid, so
				// we delay the allocation and copy to output slice until we
				// really need to do it, then copy all the so-far valid
				// files to it.
				out = make([]FileInfo, i, len(files)-1)
				copy(out, files)
			}
			continue
		}

		// Fixup the path separators
		files[i].Name = filepath.FromSlash(files[i].Name)

		if out != nil {
			out = append(out, files[i])
		}
	}

	if out != nil {
		// We did some filtering
		return out
	}

	// Unchanged
	return files
}
