import time
import traceback

import pythoncom
import win32com.client
import win32com.client.gencache
import win32con

constants = win32com.client.constants

win32com.client.gencache.EnsureModule("{783CD4E0-9D54-11CF-B8EE-00608CC9A71F}", 0, 5, 0)


def GetSS():
    ss = win32com.client.Dispatch("SourceSafe")
    # SS seems a bit weird.  It defaults the arguments as empty strings, but
    # then complains when they are used - so we pass "Missing"
    ss.Open(pythoncom.Missing, pythoncom.Missing, pythoncom.Missing)
    return ss


def test(projectName):
    ss = GetSS()
    project = ss.VSSItem(projectName)

    for item in project.GetVersions(constants.VSSFLAG_RECURSYES):
        print(item.VSSItem.Name, item.VersionNumber, item.Action)

    # item=i.Versions[0].VSSItem
    # for h in i.Versions:
    #     print("h.Comment", h.Action, h.VSSItem.Name)


def SubstituteInString(inString, evalEnv):
    substChar = "$"
    fields = inString.split(substChar)
    newFields = []
    for i in range(len(fields)):
        didSubst = 0
        strVal = fields[i]
        if i % 2 != 0:
            try:
                strVal = eval(strVal, evalEnv[0], evalEnv[1])
                newFields.append(strVal)
                didSubst = 1
            except:
                traceback.print_exc()
                print("Could not substitute", strVal)
        if not didSubst:
            newFields.append(strVal)
    return "".join(map(str, newFields))


def SubstituteInFile(inName, outName, evalEnv):
    inFile = open(inName, "r")
    try:
        outFile = open(outName, "w")
        try:
            while 1:
                line = inFile.read()
                if not line:
                    break
                outFile.write(SubstituteInString(line, evalEnv))
        finally:
            outFile.close()
    finally:
        inFile.close()


def VssLog(project, linePrefix="", noLabels=5, maxItems=150):
    lines = []
    num = 0
    labelNum = 0
    for i in project.GetVersions(constants.VSSFLAG_RECURSYES):
        num += 1
        if num > maxItems:
            break
        commentDesc = itemDesc = ""
        if i.Action[:5] == "Added":
            continue
        if len(i.Label):
            labelNum += 1
            itemDesc = i.Action
        else:
            itemDesc = i.VSSItem.Name
            if str(itemDesc[-4:]) == ".dsp":
                continue
        if i.Comment:
            commentDesc = f"\n{linePrefix}\t{i.Comment}"
        lines.append(
            "{}{}\t{}{}".format(
                linePrefix,
                time.asctime(time.localtime(int(i.Date))),
                itemDesc,
                commentDesc,
            )
        )
        if labelNum > noLabels:
            break
    return "\n".join(lines)


def SubstituteVSSInFile(projectName, inName, outName):
    import win32api

    if win32api.GetFullPathName(inName) == win32api.GetFullPathName(outName):
        raise RuntimeError("The input and output filenames can not be the same")
    sourceSafe = GetSS()
    project = sourceSafe.VSSItem(projectName)
    # Find the last label
    label = None
    for version in project.Versions:
        if version.Label:
            break
    else:
        print("Couldn't find a label in the sourcesafe project!")
        return
    # Setup some local helpers for the conversion strings.
    vss_label = version.Label
    vss_date = time.asctime(time.localtime(int(version.Date)))
    now = time.asctime(time.localtime(time.time()))
    SubstituteInFile(inName, outName, (locals(), globals()))


def CountCheckouts(item):
    num = 0
    if item.Type == constants.VSSITEM_PROJECT:
        for sub in item.Items:
            num += CountCheckouts(sub)
    else:
        if item.IsCheckedOut:
            num += 1
    return num


def GetLastBuildNo(project):
    i = GetSS().VSSItem(project)
    # Find the last label
    lab = None
    for version in i.Versions:
        lab = str(version.Label)
        if lab:
            return lab
    return None


def MakeNewBuildNo(project, buildDesc=None, auto=0, bRebrand=0):
    if buildDesc is None:
        buildDesc = "Created by Python"
    ss = GetSS()
    i = ss.VSSItem(project)
    num = CountCheckouts(i)
    if num > 0:
        msg = (
            "This project has %d items checked out\r\n\r\nDo you still want to continue?"
            % num
        )
        import win32ui

        if win32ui.MessageBox(msg, project, win32con.MB_YESNO) != win32con.IDYES:
            return

    oldBuild = buildNo = GetLastBuildNo(project)
    if buildNo is None:
        buildNo = "1"
        oldBuild = "<None>"
    else:
        try:
            buildNo = int(buildNo)
            if not bRebrand:
                buildNo += 1
            buildNo = str(buildNo)
        except ValueError as error:
            raise ValueError(
                f"The previous label could not be incremented: {oldBuild}"
            ) from error

    if not auto:
        from pywin.mfc import dialog

        buildNo = dialog.GetSimpleInput(
            "Enter new build number", buildNo, f"{project} - Prev: {oldBuild}"
        )
        if buildNo is None:
            return
    i.Label(buildNo, f"Build {buildNo}: {buildDesc}")
    if auto:
        print(f"Branded project {project} with label {buildNo}")
    return buildNo


if __name__ == "__main__":
    # 	UpdateWiseExeName("PyWiseTest.wse", "PyWiseTest-10.exe")

    # 	MakeVersion()
    # 	test(tp)
    # 	MakeNewBuildNo(tp)
    tp = "\\Python\\Python Win32 Extensions"
    SubstituteVSSInFile(
        tp, "d:\\src\\pythonex\\win32\\win32.txt", "d:\\temp\\win32.txt"
    )
