[CmdletBinding()]
param(
    [int]$MachineStart = 1,
    [int]$MachineEnd = 20,
    [string[]]$Attributes = @(
        "ProtectedValue",
        "TestChangingInt",
        "TestBoolArray",
        "TestIntArray",
        "TestDateTimeArray",
        "TestStringArray"
    ),
    [string]$SqlServer = "localhost",
    [string]$Database = "ZB",
    [string]$SqlcmdPath = "C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\130\Tools\Binn\SQLCMD.EXE",
    [switch]$Json
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

if ($MachineStart -lt 1 -or $MachineEnd -lt $MachineStart) {
    throw "MachineStart must be at least 1 and MachineEnd must be greater than or equal to MachineStart."
}

$Attributes = @($Attributes | ForEach-Object {
    $_ -split ","
} | ForEach-Object {
    $_.Trim()
} | Where-Object {
    -not [string]::IsNullOrWhiteSpace($_)
})

if ($Attributes.Count -eq 0) {
    throw "At least one attribute name is required."
}

if (-not (Test-Path -LiteralPath $SqlcmdPath)) {
    throw "sqlcmd was not found at '$SqlcmdPath'. Pass -SqlcmdPath or update docs/ToolchainLinks.md."
}

$attributeList = ($Attributes | ForEach-Object {
    "'" + $_.Replace("'", "''") + "'"
}) -join ","

$query = @"
SET NOCOUNT ON;
;WITH deployed_package_chain AS (
    SELECT g.gobject_id, p.package_id, p.derived_from_package_id, 0 AS depth
    FROM gobject g
    INNER JOIN package p ON p.package_id = g.deployed_package_id
    WHERE g.is_template = 0 AND g.deployed_package_id <> 0
    UNION ALL
    SELECT dpc.gobject_id, p.package_id, p.derived_from_package_id, dpc.depth + 1
    FROM deployed_package_chain dpc
    INNER JOIN package p ON p.package_id = dpc.derived_from_package_id
    WHERE dpc.derived_from_package_id <> 0 AND dpc.depth < 10
), ranked_dynamic AS (
    SELECT
        dpc.gobject_id,
        g.tag_name,
        da.attribute_name,
        g.tag_name + '.' + da.attribute_name
            + CASE WHEN da.is_array = 1 THEN '[]' ELSE '' END AS full_tag_reference,
        da.mx_data_type,
        dt.description AS data_type_name,
        da.is_array,
        CASE WHEN da.is_array = 1
             THEN CONVERT(int, CONVERT(varbinary(2),
                  SUBSTRING(da.mx_value, 15, 2) + SUBSTRING(da.mx_value, 13, 2), 2))
             ELSE NULL
        END AS array_dimension,
        da.security_classification,
        ROW_NUMBER() OVER (
            PARTITION BY dpc.gobject_id, da.attribute_name
            ORDER BY dpc.depth
        ) AS rn
    FROM deployed_package_chain dpc
    INNER JOIN dynamic_attribute da ON da.package_id = dpc.package_id
    INNER JOIN gobject g ON g.gobject_id = dpc.gobject_id
    LEFT JOIN data_type dt ON dt.mx_data_type = da.mx_data_type
    WHERE g.tag_name LIKE 'TestMachine[_][0-9][0-9][0-9]'
      AND TRY_CONVERT(int, RIGHT(g.tag_name, 3)) BETWEEN $MachineStart AND $MachineEnd
      AND da.attribute_name IN ($attributeList)
)
SELECT tag_name, attribute_name, full_tag_reference, mx_data_type, data_type_name,
       is_array, COALESCE(CONVERT(varchar(12), array_dimension), '') AS array_dimension,
       security_classification
FROM ranked_dynamic
WHERE rn = 1
ORDER BY tag_name, attribute_name;
"@

$output = & $SqlcmdPath -S $SqlServer -d $Database -E -W -h -1 -s "|" -Q $query
if ($LASTEXITCODE -ne 0) {
    throw "Galaxy Repository tag discovery failed with exit code $LASTEXITCODE."
}

$rows = foreach ($line in $output) {
    if ([string]::IsNullOrWhiteSpace($line)) {
        continue
    }

    $parts = $line -split "\|", 8
    if ($parts.Count -ne 8) {
        continue
    }

    [pscustomobject]@{
        tagName = $parts[0]
        attributeName = $parts[1]
        fullTagReference = $parts[2]
        mxDataType = [int]$parts[3]
        dataTypeName = $parts[4]
        isArray = $parts[5] -eq "1"
        arrayDimension = if ([string]::IsNullOrWhiteSpace($parts[6])) { $null } else { [int]$parts[6] }
        securityClassification = [int]$parts[7]
    }
}

if ($Json) {
    $rows | ConvertTo-Json -Depth 4
    return
}

$rows | Format-Table -AutoSize
