local LrApplication = import 'LrApplication'
local LrBinding = import 'LrBinding'
local LrDialogs = import 'LrDialogs'
local LrFunctionContext = import 'LrFunctionContext'
local LrView = import 'LrView'

local Catalog = require 'Catalog'
local Platform = require 'Platform'
local Prefs = require 'Prefs'

local Settings = {}

local function makeProps(context, config)
    local props = LrBinding.makePropertyTable(context)
    for k, v in pairs(config) do props[k] = v end
    return props
end

function Settings.show()
    LrFunctionContext.callWithContext('PairsSettings', function(context)
        local catalog = LrApplication.activeCatalog()
        local config = Prefs.config()
        local props = makeProps(context, config)
        local f = LrView.osFactory()

        local collectionItems = Catalog.collectionMenuItems(catalog, true)
        local setItems = Catalog.collectionSetMenuItems(catalog, true)

        local sourceRows = f:column {
            spacing = f:control_spacing(),
            f:row {
                f:static_text { title = 'Source mode:', width = 180 },
                f:popup_menu {
                    value = LrView.bind('sourceMode'),
                    items = {
                        { title = 'Current Library view (snapshot)', value = 'current' },
                        { title = 'Single collection', value = 'single' },
                        { title = 'Two collections — one per side', value = 'split' },
                    },
                },
            },
            f:row {
                f:static_text { title = 'Source (single):', width = 180 },
                f:popup_menu {
                    value = LrView.bind('sourceCollectionId'),
                    items = collectionItems,
                    width_in_chars = 32,
                },
            },
            f:row {
                f:static_text { title = 'Source left (split):', width = 180 },
                f:popup_menu {
                    value = LrView.bind('sourceCollectionLeftId'),
                    items = collectionItems,
                    width_in_chars = 32,
                },
            },
            f:row {
                f:static_text { title = 'Source right (split):', width = 180 },
                f:popup_menu {
                    value = LrView.bind('sourceCollectionRightId'),
                    items = collectionItems,
                    width_in_chars = 32,
                },
            },
            f:row {
                f:static_text { title = 'Save pairs to (collection set):', width = 180 },
                f:popup_menu {
                    value = LrView.bind('targetSetId'),
                    items = setItems,
                    width_in_chars = 32,
                },
            },
            -- Help text under the dropdown: an LR collection set is
            -- its own thing (not a collection) and users may have
            -- none until they create one.  The dropdown lists only
            -- existing sets, so if the list is empty the user has
            -- to leave this dialog, create a set in Lightroom, and
            -- come back.  Spelling that out here is worth the
            -- extra line.  (A future one-click "create set" button
            -- on the Dashboard is tracked in IDEAS.md.)
            f:row {
                f:static_text { title = '', width = 180 },
                f:static_text {
                    title = 'A collection set groups saved pairs as '
                        .. '"Pair 0001", "Pair 0002", etc.  If the '
                        .. 'list above is empty, create a collection '
                        .. 'set in Lightroom first, then reopen.',
                    text_color = LrView.kColorGrey,
                    width_in_chars = 48,
                    height_in_lines = 3,
                },
            },
        }

        local filterRows = f:column {
            spacing = f:control_spacing(),
            f:row {
                f:static_text { title = 'Min rating:', width = 180 },
                f:popup_menu {
                    value = LrView.bind('minRating'),
                    items = {
                        { title = 'Any', value = 0 },
                        { title = '1 star+', value = 1 },
                        { title = '2 stars+', value = 2 },
                        { title = '3 stars+', value = 3 },
                        { title = '4 stars+', value = 4 },
                        { title = '5 stars',  value = 5 },
                    },
                },
            },
            f:row {
                f:static_text { title = 'Required flag:', width = 180 },
                f:popup_menu {
                    value = LrView.bind('requiredFlag'),
                    items = {
                        { title = 'Either',    value = 'either' },
                        { title = 'Pick',      value = 'pick' },
                        { title = 'Unflagged', value = 'unflagged' },
                    },
                },
            },
            f:row {
                f:static_text { title = 'Color label:', width = 180 },
                f:popup_menu {
                    value = LrView.bind('requiredColorLabel'),
                    items = {
                        { title = 'Any',    value = 'any' },
                        { title = 'Red',    value = 'red' },
                        { title = 'Yellow', value = 'yellow' },
                        { title = 'Green',  value = 'green' },
                        { title = 'Blue',   value = 'blue' },
                        { title = 'Purple', value = 'purple' },
                        { title = 'None',   value = 'none' },
                    },
                },
            },
            f:row {
                f:static_text { title = 'Orientation:', width = 180 },
                f:popup_menu {
                    value = LrView.bind('poolOrientation'),
                    items = {
                        { title = 'Any',       value = 'any' },
                        { title = 'Landscape', value = 'landscape' },
                        { title = 'Portrait',  value = 'portrait' },
                        { title = 'Square',    value = 'square' },
                    },
                },
            },
            -- "Allow mixed orientation" used to live in its own
            -- Pairing tab.  Moved here because (a) Pairing held
            -- only this one checkbox, not enough to defend a
            -- tab of its own, and (b) this rule semantically
            -- neighbours Orientation above — they both govern
            -- how orientation constrains what the user sees.
            --
            -- Enabled only when Orientation is 'Any'.  The
            -- checkbox is meaningless for a single-orientation
            -- pool (pool contains only landscapes, so a pair
            -- can't mix orientations regardless of this flag).
            -- Leaving the stored value alone when disabled, so
            -- the user's preference survives a round-trip
            -- through a filter change.
            f:row {
                f:static_text { title = '', width = 180 },
                f:checkbox {
                    title = 'Allow mixed orientation pairs',
                    value = LrView.bind('allowMixedOrientation'),
                    enabled = LrView.bind {
                        key = 'poolOrientation',
                        transform = function(value)
                            return value == 'any'
                        end,
                    },
                },
            },
        }

        local layoutRows = f:column {
            spacing = f:control_spacing(),
            f:row {
                f:static_text { title = 'Background:', width = 180 },
                f:popup_menu {
                    value = LrView.bind('colorScheme'),
                    items = {
                        { title = 'White', value = 'white' },
                        { title = 'Grey',  value = 'grey' },
                        { title = 'Black', value = 'black' },
                    },
                },
            },
            f:row {
                -- "Minimum image size", not "Image size":
                -- `LrPhoto:requestJpegThumbnail(w, h)` returns
                -- whatever cached preview LR has if the cached
                -- size is larger than what we asked for
                -- (verified: requesting 1024 returned a
                -- 1876x1250 JPEG on a catalog with large
                -- standard previews).  So this value is a
                -- floor — the minimum sharpness the plugin
                -- asks for — not a cap.  Raising it forces LR
                -- to build from source if cached previews are
                -- smaller; that code path hangs
                -- intermittently on Windows, hence the help
                -- text below.
                f:static_text { title = 'Minimum image size:', width = 180 },
                f:popup_menu {
                    value = LrView.bind('imageSize'),
                    -- Values mirror LR's own "Standard Preview
                    -- Size" options exactly, so users can pick a
                    -- floor that matches what their catalog
                    -- already caches.  Default 1024 is the most
                    -- conservative — fits every realistic LR
                    -- standard-preview setting.
                    items = {
                        { title = '1024 px', value = 1024 },
                        { title = '1440 px', value = 1440 },
                        { title = '1680 px', value = 1680 },
                        { title = '2048 px', value = 2048 },
                        { title = '2880 px', value = 2880 },
                    },
                },
            },
            f:row {
                f:static_text { title = '', width = 180 },
                f:static_text {
                    -- Menu path to Catalog Settings differs per
                    -- OS (Mac mounts it under the LR Classic
                    -- app menu, Windows under Edit), so we show
                    -- the OS-correct path to the running user.
                    -- Wording stays "raise" because the setting
                    -- is a floor — if LR's cached previews are
                    -- below the chosen floor, LR has to rebuild.
                    title = (function()
                        local path = Platform.isWindows
                            and 'Edit → Catalog Settings → Previews'
                            or 'Lightroom Classic → Catalog Settings → Previews'
                        return
                            'LR returns whatever\'s cached if it\'s '
                            .. 'bigger than this size.  If pair loading '
                            .. 'is slow or stalls, raise your catalog\'s '
                            .. 'Standard Preview Size ('
                            .. path .. ') and rebuild standard previews '
                            .. 'for your source set.'
                    end)(),
                    text_color = LrView.kColorGrey,
                    width_in_chars = 55,
                    height_in_lines = 4,
                },
            },
        }

        -- ---- Browser tab ---------------------------------
        --
        -- Browser preference for the pair window.  Auto picks
        -- a running Chromium browser (no cold-start lag); a
        -- specific name forces that browser even if cold.
        -- Items are filtered to "Auto" + browsers actually
        -- installed on this machine — no point offering Edge
        -- if it's not present.  See ideas/focus-cohesion.md
        -- "Smarter browser choice" for the full design.
        --
        -- Two tiers in the dropdown:
        --   - Chromium-family (Chrome, Edge, Brave, Chromium):
        --     get the minimal --app window.  Listed bare.
        --   - Non-Chromium (Firefox, Safari): open as a
        --     regular browser tab.  Listed with "(regular
        --     tab)" suffix so users know what they're
        --     picking.
        local LrFileUtils = import 'LrFileUtils'
        local browserItems = { { title = 'Auto', value = 'auto' } }
        local PREF_FROM_NAME = {
            ['Google Chrome']  = 'chrome',
            ['Microsoft Edge'] = 'edge',
            ['Brave Browser']  = 'brave',
            ['Arc']            = 'arc',
            ['Chromium']       = 'chromium',
            ['Firefox']        = 'firefox',
            ['Safari']         = 'safari',
        }
        -- Set of pref values that ARE going to appear in the
        -- final dropdown — used to validate the persisted
        -- pref value below.  'auto' is always present.
        local validPrefs = { auto = true }
        local anyChromium = false
        for _, b in ipairs(Platform.chromiumBrowsers()) do
            if LrFileUtils.exists(b.bin) then
                local pref = PREF_FROM_NAME[b.name]
                if pref and not validPrefs[pref] then
                    -- "(minimal window)" suffix so the user
                    -- knows this opens the pair view as a
                    -- custom-looking window, not a regular
                    -- browser tab.  Pairs with the
                    -- "(regular tab)" suffix on non-Chromium
                    -- entries below — every dropdown item
                    -- self-describes its launch mode.
                    browserItems[#browserItems + 1] =
                        { title = b.name .. ' (minimal window)',
                          value = pref }
                    validPrefs[pref] = true
                    anyChromium = true
                end
            end
        end
        for _, b in ipairs(Platform.regularBrowsers()) do
            if LrFileUtils.exists(b.bin) then
                local pref = PREF_FROM_NAME[b.name]
                if pref and not validPrefs[pref] then
                    -- not validPrefs check avoids dupes
                    -- (e.g. Windows Firefox listed twice in
                    -- regularBrowsers for two install paths)
                    browserItems[#browserItems + 1] =
                        { title = b.name .. ' (regular tab)',
                          value = pref }
                    validPrefs[pref] = true
                end
            end
        end

        -- Validate the persisted pref against the items we're
        -- about to show.  If the user previously picked a
        -- browser that's no longer installed (renamed,
        -- deleted, etc.), the popup_menu would render blank
        -- because no item matches the bound value.  Reset to
        -- 'auto' so the dropdown shows a sensible default.
        if not validPrefs[props.browserPref] then
            props.browserPref = 'auto'
        end
        local browserRows = f:column {
            spacing = f:control_spacing(),
            f:row {
                f:static_text { title = 'Browser:', width = 180 },
                f:popup_menu {
                    value = LrView.bind('browserPref'),
                    items = browserItems,
                },
            },
            -- Warning row when no Chromium browser is
            -- installed — the dropdown is just "Auto" plus
            -- maybe Firefox/Safari, and Auto will end up
            -- routing to the system default browser since
            -- there's no Chromium available.  Heads off
            -- "why is my pair window opening as a regular
            -- tab" confusion before it happens.
            (not anyChromium) and f:row {
                f:static_text { title = '', width = 180 },
                f:static_text {
                    title =
                        'No Chrome / Edge / Brave detected — '
                        .. 'Auto will launch your default '
                        .. 'browser as a regular tab.',
                    text_color = LrView.kColorGrey,
                    font = '<system/bold>',
                    width_in_chars = 60,
                    height_in_lines = 2,
                },
            } or f:spacer { height = 0 },
            -- Lead help paragraph: explain why the plugin
            -- needs a browser at all.  Sourced from the
            -- README "What you'll see" callout — testers
            -- shouldn't have to read the README to
            -- understand what this setting is for.
            f:row {
                f:static_text { title = '', width = 180 },
                f:static_text {
                    title =
                        'The Pair Generator opens in a '
                        .. 'browser window because Lightroom\'s '
                        .. 'plugin UI toolkit can\'t render the '
                        .. 'side-by-side photo comparison '
                        .. 'cleanly.  This setting controls '
                        .. 'which browser is used.',
                    text_color = LrView.kColorGrey,
                    width_in_chars = 60,
                    height_in_lines = 3,
                },
            },
            f:row {
                f:static_text { title = '', width = 180 },
                f:static_text {
                    title =
                        'Chrome and Edge (Chromium-based '
                        .. 'browsers) open the Pair Generator '
                        .. 'window as a minimal window, '
                        .. 'without browser tabs or address '
                        .. 'bar.  Other browsers open it as a '
                        .. 'regular tab.',
                    text_color = LrView.kColorGrey,
                    width_in_chars = 60,
                    height_in_lines = 3,
                },
            },
            f:row {
                f:static_text { title = '', width = 180 },
                f:static_text {
                    title =
                        'Auto prefers a Chromium browser '
                        .. 'that\'s already running, so the '
                        .. 'first launch is fast, and falls '
                        .. 'back to Chrome if available, '
                        .. 'otherwise Edge, otherwise Brave.',
                    text_color = LrView.kColorGrey,
                    width_in_chars = 60,
                    height_in_lines = 3,
                },
            },
            -- (Earlier builds had a third paragraph about
            -- "Edge has slightly better Lightroom
            -- integration than Chrome" — turned out to be a
            -- false diagnosis: the original Chrome failure
            -- was a stale-JS-cache bug, not a real Chrome
            -- pagehide quirk.  Build 81's content-hashing
            -- fix made the pagehide listener actually load
            -- in Chrome too.  No actual Chrome-vs-Edge
            -- difference for focus-on-close behavior;
            -- paragraph removed.)
        }

        local contents = f:view {
            bind_to_object = props,
            f:tab_view {
                f:tab_view_item { title = 'Sources & target', identifier = 'sources',  sourceRows },
                f:tab_view_item { title = 'Filters',          identifier = 'filters',  filterRows },
                f:tab_view_item { title = 'Display',          identifier = 'display',  layoutRows },
                f:tab_view_item { title = 'Browser',          identifier = 'browser',  browserRows },
            },
        }

        local result = LrDialogs.presentModalDialog {
            title = 'Random Pair Generator settings',
            contents = contents,
            actionVerb = 'Save',
        }

        if result == 'ok' then
            local updates = {}
            for k in pairs(config) do updates[k] = props[k] end
            Prefs.setConfig(updates)
        end
    end)
end

return Settings
