package segments

import (
	"errors"

	"github.com/jandedobbeleer/oh-my-posh/src/runtime"
	"github.com/jandedobbeleer/oh-my-posh/src/shell"
)

const (
	fooBarMan = "\\foo\\bar\\man"
)

var testParentCases = []testParentCase{
	{
		Case:          "Windows Home folder",
		HomePath:      homeDirWindows,
		Pwd:           homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows drive root",
		HomePath:      homeDirWindows,
		Pwd:           "C:",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows drive root with a trailing separator",
		HomePath:      homeDirWindows,
		Pwd:           "C:\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows drive root + 1",
		Expected:      "C:\\",
		HomePath:      homeDirWindows,
		Pwd:           "C:\\test",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "PSDrive root",
		HomePath:      homeDirWindows,
		Pwd:           "HKLM:",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
}

var testAgnosterPathStyleCases = []testAgnosterPathStyleCase{
	{
		Style:               Unique,
		Expected:            "C > a > ab > abcd",
		HomePath:            homeDirWindows,
		Pwd:                 "C:\\ab\\ab\\abcd",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
	},
	{
		Style:               Letter,
		Expected:            "C: > ",
		HomePath:            homeDirWindows,
		Pwd:                 "C:\\",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
	},
	{
		Style:               Letter,
		Expected:            "C > s > .w > man",
		HomePath:            homeDirWindows,
		Pwd:                 "C:\\something\\.whatever\\man",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
	},
	{
		Style:               Letter,
		Expected:            "~ > s > man",
		HomePath:            homeDirWindows,
		Pwd:                 homeDirWindows + "\\something\\man",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
	},
	{
		Style:               Mixed,
		Expected:            "C: > .. > foo > .. > man",
		HomePath:            homeDirWindows,
		Pwd:                 "C:\\Users\\foo\\foobar\\man",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
	},
	{
		Style:               Mixed,
		Expected:            "c > .. > foo > .. > man",
		HomePath:            homeDirWindows,
		Pwd:                 "C:\\Users\\foo\\foobar\\man",
		GOOS:                runtime.WINDOWS,
		Shell:               shell.BASH,
		Cygwin:              true,
		Cygpath:             "/c/Users/foo/foobar/man",
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
	},
	{
		Style:               Mixed,
		Expected:            "C: > .. > foo > .. > man",
		HomePath:            homeDirWindows,
		Pwd:                 "C:\\Users\\foo\\foobar\\man",
		GOOS:                runtime.WINDOWS,
		Shell:               shell.BASH,
		CygpathError:        errors.New("oh no"),
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
	},
	{
		Style:               AgnosterShort,
		Expected:            "\\\\localhost\\c$ > some",
		HomePath:            homeDirWindows,
		Pwd:                 "\\\\localhost\\c$\\some",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
	},
	{
		Style:               AgnosterShort,
		Expected:            "\\\\localhost\\c$",
		HomePath:            homeDirWindows,
		Pwd:                 "\\\\localhost\\c$",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
	},
	{
		Style:               AgnosterShort,
		Expected:            ".. > bar > man",
		HomePath:            homeDirWindows,
		Pwd:                 homeDirWindows + fooBarMan,
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
		MaxDepth:            2,
		HideRootLocation:    true,
	},
	{
		Style:               AgnosterShort,
		Expected:            "C: > ",
		HomePath:            homeDirWindows,
		Pwd:                 "C:",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
	},
	{
		Style:               AgnosterShort,
		Expected:            "C: > .. > bar > man",
		HomePath:            homeDirWindows,
		Pwd:                 "C:\\usr\\foo\\bar\\man",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
		MaxDepth:            2,
	},
	{
		Style:               AgnosterShort,
		Expected:            "C: > .. > foo > bar > man",
		HomePath:            homeDirWindows,
		Pwd:                 "C:\\usr\\foo\\bar\\man",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
		MaxDepth:            3,
	},
	{
		Style:               AgnosterShort,
		Expected:            "~ > .. > bar > man",
		HomePath:            homeDirWindows,
		Pwd:                 homeDirWindows + fooBarMan,
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
		MaxDepth:            2,
	},
	{
		Style:               AgnosterShort,
		Expected:            "~ > foo > bar > man",
		HomePath:            homeDirWindows,
		Pwd:                 homeDirWindows + fooBarMan,
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
		MaxDepth:            3,
	},
	{
		Style:               AgnosterShort,
		Expected:            "~",
		HomePath:            homeDirWindows,
		Pwd:                 homeDirWindows,
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
		MaxDepth:            1,
		HideRootLocation:    true,
	},
	{
		Style:               AgnosterShort,
		Expected:            ".. > foo",
		HomePath:            homeDirWindows,
		Pwd:                 homeDirWindows + "\\foo",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
		MaxDepth:            1,
		HideRootLocation:    true,
	},
	{
		Style:               AgnosterShort,
		Expected:            "~ > foo",
		HomePath:            homeDirWindows,
		Pwd:                 homeDirWindows + "\\foo",
		GOOS:                runtime.WINDOWS,
		PathSeparator:       `\`,
		FolderSeparatorIcon: " > ",
		MaxDepth:            2,
		HideRootLocation:    true,
	},
}

var testAgnosterPathCases = []testAgnosterPathCase{
	{
		Case:          "Windows registry drive case sensitive",
		Expected:      "\uf013 > f > magnetic:TOAST",
		Home:          homeDirWindows,
		PWD:           "HKLM:\\SOFTWARE\\magnetic:TOAST\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows outside home",
		Expected:      "C: > f > f > location",
		Home:          homeDirWindows,
		PWD:           "C:\\Program Files\\Go\\location",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows outside home",
		Expected:      "~ > f > f > location",
		Home:          homeDirWindows,
		PWD:           homeDirWindows + "\\Documents\\Bill\\location",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows inside home zero levels",
		Expected:      "C: > location",
		Home:          homeDirWindows,
		PWD:           "C:\\location",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows inside home one level",
		Expected:      "C: > f > location",
		Home:          homeDirWindows,
		PWD:           "C:\\Program Files\\location",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows lower case drive letter",
		Expected:      "C: > Windows",
		Home:          homeDirWindows,
		PWD:           "C:\\Windows\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows lower case drive letter (other)",
		Expected:      "P: > Other",
		Home:          homeDirWindows,
		PWD:           "P:\\Other\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows lower word drive",
		Expected:      "some: > some",
		Home:          homeDirWindows,
		PWD:           "some:\\some\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows lower word drive (ending with c)",
		Expected:      "src: > source",
		Home:          homeDirWindows,
		PWD:           "src:\\source\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows lower word drive (arbitrary cases)",
		Expected:      "sRc: > source",
		Home:          homeDirWindows,
		PWD:           "sRc:\\source\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows registry drive",
		Expected:      "\uf013 > f > magnetic:test",
		Home:          homeDirWindows,
		PWD:           "HKLM:\\SOFTWARE\\magnetic:test\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
}

var testAgnosterLeftPathCases = []testAgnosterLeftPathCase{
	{
		Case:          "Windows inside home",
		Expected:      "~ > Documents > f > f",
		Home:          homeDirWindows,
		PWD:           homeDirWindows + "\\Documents\\Bill\\location",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows outside home",
		Expected:      "C: > Program Files > f > f",
		Home:          homeDirWindows,
		PWD:           "C:\\Program Files\\Go\\location",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows inside home zero levels",
		Expected:      "C: > location",
		Home:          homeDirWindows,
		PWD:           "C:\\location",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows inside home one level",
		Expected:      "C: > Program Files > f",
		Home:          homeDirWindows,
		PWD:           "C:\\Program Files\\location",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows lower case drive letter",
		Expected:      "C: > Windows",
		Home:          homeDirWindows,
		PWD:           "C:\\Windows\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows lower case drive letter (other)",
		Expected:      "P: > Other",
		Home:          homeDirWindows,
		PWD:           "P:\\Other\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows lower word drive",
		Expected:      "some: > some",
		Home:          homeDirWindows,
		PWD:           "some:\\some\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows lower word drive (ending with c)",
		Expected:      "src: > source",
		Home:          homeDirWindows,
		PWD:           "src:\\source\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows lower word drive (arbitrary cases)",
		Expected:      "sRc: > source",
		Home:          homeDirWindows,
		PWD:           "sRc:\\source\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows registry drive",
		Expected:      "\uf013 > SOFTWARE > f",
		Home:          homeDirWindows,
		PWD:           "HKLM:\\SOFTWARE\\magnetic:test\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
	{
		Case:          "Windows registry drive case sensitive",
		Expected:      "\uf013 > SOFTWARE > f",
		Home:          homeDirWindows,
		PWD:           "HKLM:\\SOFTWARE\\magnetic:TOAST\\",
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
	},
}

var testFullAndFolderPathCases = []testFullAndFolderPathCase{
	{Style: FolderType, FolderSeparatorIcon: `\`, Pwd: "C:\\", Expected: "C:\\", PathSeparator: `\`, GOOS: runtime.WINDOWS},
	{Style: FolderType, FolderSeparatorIcon: `\`, Pwd: "\\\\localhost\\d$", Expected: "\\\\localhost\\d$", PathSeparator: `\`, GOOS: runtime.WINDOWS},
	{Style: FolderType, FolderSeparatorIcon: `\`, Pwd: homeDirWindows, Expected: "~", PathSeparator: `\`, GOOS: runtime.WINDOWS},
	{Style: Full, FolderSeparatorIcon: `\`, Pwd: homeDirWindows, Expected: "~", PathSeparator: `\`, GOOS: runtime.WINDOWS},
	{Style: Full, FolderSeparatorIcon: `\`, Pwd: homeDirWindows + "\\abc", Expected: "~\\abc", PathSeparator: `\`, GOOS: runtime.WINDOWS},
	{Style: Full, FolderSeparatorIcon: `\`, Pwd: "C:\\Users\\posh", Expected: "C:\\Users\\posh", PathSeparator: `\`, GOOS: runtime.WINDOWS},

	// A folder name containing template syntax must never execute the `cmd` function
	// once it is spliced into pt.Path and re-rendered in setStyle(): the render uses
	// the restricted func map, so parsing fails and pt.Path keeps its raw, unexecuted
	// text instead.
	{
		Style: FolderType, FolderSeparatorIcon: `\`,
		Pwd: homeDirWindows + "\\{{ cmd `whoami` }}", Expected: "{{ cmd `whoami` }}",
		PathSeparator: `\`, GOOS: runtime.WINDOWS,
	},
}

var testFullPathCustomMappedLocationsCases = []testFullPathCustomMappedLocationsCase{
	{
		Pwd:             `\a\b\c\d`,
		MappedLocations: map[string]string{`\a\b`: "#"},
		GOOS:            runtime.WINDOWS,
		PathSeparator:   `\`,
		Expected:        `#\c\d`,
	},
	{
		Pwd:             `\a\b\1234\d\e`,
		MappedLocations: map[string]string{`re:(/a/b/[0-9]+/d).*`: "#"},
		GOOS:            runtime.WINDOWS,
		PathSeparator:   `\`,
		Expected:        `#\e`,
	},
	{
		Pwd:             `\a\b\1234\f\e`,
		MappedLocations: map[string]string{`re:(/a/b/[0-9]+/d).*`: "#"},
		GOOS:            runtime.WINDOWS,
		PathSeparator:   `\`,
		Expected:        `\a\b\1234\f\e`,
	},
	{
		Pwd:             `C:\Users\taylo\Documents\github\project`,
		MappedLocations: map[string]string{`re:(.*Users/taylo/Documents/GitHub).*`: "github"},
		GOOS:            runtime.WINDOWS,
		PathSeparator:   `\`,
		Expected:        `github\project`,
	},
	// mapped_locations_regex_expand=true composes with the (?i) Windows/WSL case-insensitivity
	// prefix: the pattern uses lowercase "github" while the actual path has "GitHub".
	{
		Pwd:                        `C:\Users\taylo\GitHub\myrepo.worktrees\feature-branch`,
		MappedLocations:            map[string]string{`re:(.*/github/(?P<repo>.*)\.worktrees/.*)`: "/${repo}"},
		MappedLocationsRegexExpand: true,
		GOOS:                       runtime.WINDOWS,
		PathSeparator:              `\`,
		Expected:                   `\myrepo`,
	},
	// legacy path replaces the occurrence at the actual match position, not the first
	// textual occurrence of the captured substring anywhere in the input.
	{
		Pwd:             `\home\src\project\src\deep`,
		MappedLocations: map[string]string{`re:.*/(src)/deep`: "#"},
		GOOS:            runtime.WINDOWS,
		PathSeparator:   `\`,
		Expected:        `\home\src\project\#\deep`,
	},
}

var testSplitPathCases = []testSplitPathCase{
	{
		Case:         "Home directory - git folder on Windows",
		Root:         "C:",
		Relative:     "a/b/c/d",
		GOOS:         runtime.WINDOWS,
		GitDir:       &runtime.FileInfo{IsDir: true, ParentFolder: "C:/a/b/c"},
		GitDirFormat: "<b>%s</b>",
		Expected: Folders{
			{Name: "a", Path: "C:/a"},
			{Name: "b", Path: "C:/a/b"},
			{Name: "<b>c</b>", Path: "C:/a/b/c", Display: true},
			{Name: "d", Path: "C:/a/b/c/d"},
		},
	},
	{
		Case:         "Home directory - linked git worktree on Windows",
		Root:         "C:",
		Relative:     "a/b/c/d",
		GOOS:         runtime.WINDOWS,
		GitDir:       &runtime.FileInfo{ParentFolder: "C:/a/b/c"},
		GitDirFormat: "<b>%s</b>",
		Expected: Folders{
			{Name: "a", Path: "C:/a"},
			{Name: "b", Path: "C:/a/b"},
			{Name: "<b>c</b>", Path: "C:/a/b/c", Display: true},
			{Name: "d", Path: "C:/a/b/c/d"},
		},
	},
}

var testNormalizePathCases = []testNormalizePathCase{
	{
		Case:          "Windows: absolute w/o drive letter, forward slash included",
		Input:         "/foo/~/bar",
		HomeDir:       homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
		Expected:      "\\foo\\~\\bar",
	},
	{
		Case:          "Windows: absolute",
		Input:         homeDirWindows + "\\Foo",
		HomeDir:       homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
		Expected:      "c:\\users\\someone\\foo",
	},
	{
		Case:          "Windows: home prefix",
		Input:         "~\\Bob\\Foo",
		HomeDir:       homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
		Expected:      "c:\\users\\someone\\bob\\foo",
	},
	{
		Case:          "Windows: home prefix",
		Input:         "~/baz",
		HomeDir:       homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
		Expected:      "c:\\users\\someone\\baz",
	},
	{
		Case:          "Windows: UNC root w/ prefix",
		Input:         `\\.\UNC\localhost\c$`,
		HomeDir:       homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
		Expected:      "\\\\localhost\\c$",
	},
	{
		Case:          "Windows: UNC root w/ prefix, forward slash included",
		Input:         "//./UNC/localhost/c$",
		HomeDir:       homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
		Expected:      "\\\\localhost\\c$",
	},
	{
		Case:          "Windows: UNC root",
		Input:         `\\localhost\c$\`,
		HomeDir:       homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
		Expected:      "\\\\localhost\\c$",
	},
	{
		Case:          "Windows: UNC root, forward slash included",
		Input:         "//localhost/c$",
		HomeDir:       homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
		Expected:      "\\\\localhost\\c$",
	},
	{
		Case:          "Windows: UNC",
		Input:         `\\localhost\c$\some`,
		HomeDir:       homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
		Expected:      "\\\\localhost\\c$\\some",
	},
	{
		Case:          "Windows: UNC, forward slash included",
		Input:         "//localhost/c$/some",
		HomeDir:       homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
		Expected:      "\\\\localhost\\c$\\some",
	},
	{
		Case:          "Windows: display Cygwin path",
		Input:         fooBarMan,
		HomeDir:       homeDirWindows,
		GOOS:          runtime.WINDOWS,
		PathSeparator: `\`,
		Expected:      "/foo/bar/man",
		Cygwin:        true,
	},
}
