#!/usr/bin/env nu
# Import from Logseq graph to KOGRAL
#
# Usage: nu kogral-import-logseq.nu <logseq-path> [--kogral-dir <path>] [--dry-run]

def main [
    logseq_path: string           # Path to Logseq graph directory
    --kogral-dir: string = ".kogral"      # KOGRAL directory
    --dry-run                     # Show what would be imported without making changes
    --skip-journals               # Skip importing journal entries
    --skip-pages                  # Skip importing pages
] {
    print $"(ansi green_bold)Logseq Import(ansi reset)"
    print $"Source: ($logseq_path)"
    print $"Target: ($kogral_dir)"

    if $dry_run {
        print $"(ansi yellow)DRY RUN MODE - No changes will be made(ansi reset)"
    }

    # Validate Logseq directory
    if not ($logseq_path | path exists) {
        print $"(ansi red)Error: Logseq path not found: ($logseq_path)(ansi reset)"
        exit 1
    }

    let pages_dir = $"($logseq_path)/pages"
    let journals_dir = $"($logseq_path)/journals"

    if not ($pages_dir | path exists) and not ($journals_dir | path exists) {
        print $"(ansi red)Error: Not a valid Logseq graph (missing pages or journals directory)(ansi reset)"
        exit 1
    }

    # Validate KOGRAL directory
    if not ($kogral_dir | path exists) {
        print $"(ansi yellow)KOGRAL directory doesn't exist. Creating...(ansi reset)"
        if not $dry_run {
            mkdir $kogral_dir
            mkdir $"($kogral_dir)/notes"
            mkdir $"($kogral_dir)/journal"
        }
    }

    # Count files to import
    let pages_count = if ($pages_dir | path exists) and not $skip_pages {
        glob $"($pages_dir)/**/*.md" | length
    } else { 0 }

    let journals_count = if ($journals_dir | path exists) and not $skip_journals {
        glob $"($journals_dir)/**/*.md" | length
    } else { 0 }

    print $"\n(ansi cyan_bold)Files to import:(ansi reset)"
    print $"  Pages:    ($pages_count)"
    print $"  Journals: ($journals_count)"
    print $"  Total:    ($pages_count + $journals_count)"

    if ($pages_count + $journals_count) == 0 {
        print $"\n(ansi yellow)No files to import(ansi reset)"
        exit 0
    }

    if $dry_run {
        print $"\n(ansi yellow)[DRY RUN] Would import ($pages_count + $journals_count) files(ansi reset)"
        exit 0
    }

    # Import pages
    if not $skip_pages and $pages_count > 0 {
        print $"\n(ansi cyan_bold)Importing pages...(ansi reset)"
        import_pages $pages_dir $kogral_dir
    }

    # Import journals
    if not $skip_journals and $journals_count > 0 {
        print $"\n(ansi cyan_bold)Importing journals...(ansi reset)"
        import_journals $journals_dir $kogral_dir
    }

    print $"\n(ansi green_bold)✓ Import completed(ansi reset)"
    print $"Imported ($pages_count + $journals_count) files"
}

def import_pages [pages_dir: string, kogral_dir: string] {
    let files = glob $"($pages_dir)/**/*.md"
    let total = $files | length

    mut imported = 0
    mut decisions = 0
    mut guidelines = 0
    mut patterns = 0
    mut notes = 0

    for file in $files {
        let filename = $file | path basename
        print $"  Importing ($filename)..."

        # Phase 1: Read and parse Logseq format
        let content = open $file

        # Phase 2: Detect node type from properties/content
        let node_type = detect_node_type $content

        # Phase 3: Convert to KOGRAL format
        let kogral_content = convert_logseq_to_kogral $content $node_type

        # Phase 4: Determine target directory
        let target_dir = match $node_type {
            "decision" => {
                $decisions = $decisions + 1
                $"($kogral_dir)/decisions"
            },
            "guideline" => {
                $guidelines = $guidelines + 1
                $"($kogral_dir)/guidelines"
            },
            "pattern" => {
                $patterns = $patterns + 1
                $"($kogral_dir)/patterns"
            },
            _ => {
                $notes = $notes + 1
                $"($kogral_dir)/notes"
            }
        }

        # Phase 5: Save to KOGRAL
        mkdir $target_dir
        $kogral_content | save $"($target_dir)/($filename)"

        $imported = $imported + 1
        print $"    (ansi green)✓ Imported as ($node_type)(ansi reset)"
    }

    print $"\n(ansi green)Pages summary:(ansi reset)"
    print $"  Notes:      ($notes)"
    print $"  Decisions:  ($decisions)"
    print $"  Guidelines: ($guidelines)"
    print $"  Patterns:   ($patterns)"
    print $"  Total:      ($imported)/($total) imported"
}

def import_journals [journals_dir: string, kogral_dir: string] {
    let files = glob $"($journals_dir)/**/*.md"
    let total = $files | length

    mkdir $"($kogral_dir)/journal"

    mut imported = 0

    for file in $files {
        let filename = $file | path basename
        print $"  Importing ($filename)..."

        # Phase 1: Read Logseq journal format
        let content = open $file

        # Phase 2: Convert to KOGRAL journal format
        let kogral_content = convert_logseq_to_kogral $content "journal"

        # Phase 3: Save to journal directory
        $kogral_content | save $"($kogral_dir)/journal/($filename)"

        $imported = $imported + 1
        print $"    (ansi green)✓ Imported(ansi reset)"
    }

    print $"\n(ansi green)Journals imported: ($imported)/($total)(ansi reset)"
}

def detect_node_type [content: string] {
    # Check for type hints in properties or content
    if ($content | str contains "type:: decision") or ($content | str contains "# Decision") {
        "decision"
    } else if ($content | str contains "type:: guideline") or ($content | str contains "# Guideline") {
        "guideline"
    } else if ($content | str contains "type:: pattern") or ($content | str contains "# Pattern") {
        "pattern"
    } else {
        "note"
    }
}

def convert_logseq_to_kogral [content: string, node_type: string] {
    let lines = $content | lines

    # Phase 1: Parse Logseq properties (key:: value format)
    let props = parse_logseq_properties $lines
    let body_start = get_body_start_index $lines

    # Phase 2: Extract metadata from properties
    let title = $props.title? | default (extract_title_from_lines $lines)
    let created = $props.created? | default (date now | format date "%Y-%m-%dT%H:%M:%SZ")
    let modified = $props.modified? | default (date now | format date "%Y-%m-%dT%H:%M:%SZ")
    let status = match ($node_type) {
        "journal" => "draft",
        _ => "active"
    }

    # Phase 3: Extract tags and relationships from properties
    let tags = parse_tags_from_properties $props
    let relates_to = parse_references_from_property ($props.relates_to? | default "")
    let depends_on = parse_references_from_property ($props.depends_on? | default "")
    let implements = parse_references_from_property ($props.implements? | default "")
    let extends = parse_references_from_property ($props.extends? | default "")

    # Phase 4: Build YAML frontmatter
    let frontmatter = build_yaml_frontmatter {
        type: $node_type,
        title: $title,
        created: $created,
        modified: $modified,
        status: $status,
        tags: $tags,
        relates_to: $relates_to,
        depends_on: $depends_on,
        implements: $implements,
        extends: $extends
    }

    # Phase 5: Extract body and preserve wikilinks
    let body = if $body_start < ($lines | length) {
        $lines | skip $body_start | str join "\n"
    } else {
        ""
    }

    # Phase 6: Convert Logseq-specific syntax
    let converted_body = convert_logseq_syntax $body

    $"$frontmatter\n$converted_body"
}

def parse_logseq_properties [lines: list] {
    mut props = {}

    # Parse properties until blank line or content starts
    for line in $lines {
        if ($line | str trim | is-empty) {
            break
        }

        # Match pattern: key:: value
        if ($line =~ '^[\w-]+::') {
            let key = $line | str replace '^(\w[\w-]*)::.*' '$1'
            let value = $line | str replace '^[\w-]+::\s*' '' | str trim
            $props = ($props | insert $key $value)
        }
    }

    $props
}

def get_body_start_index [lines: list] {
    # Find where properties end (first blank line or non-property line)
    mut idx = 0

    for line in $lines {
        if ($line | str trim | is-empty) {
            return ($idx + 1)
        }

        if not ($line =~ '^[\w-]+::') and ($line | str trim | length) > 0 {
            return $idx
        }

        $idx = $idx + 1
    }

    $idx
}

def extract_title_from_lines [lines: list] {
    # Extract from first heading or property
    for line in $lines {
        if ($line =~ '^#+ ') {
            return ($line | str replace '^#+\s+' '')
        }

        if ($line =~ '^title::') {
            return ($line | str replace '^title::\s*' '')
        }
    }

    "Untitled"
}

def parse_tags_from_properties [props: record] {
    mut tags = []

    # Check tags property
    if ($props.tags? | is-empty) {
        return $tags
    }

    let tags_str = $props.tags?

    # Extract [[tag]] format using split
    if ($tags_str | str contains "[[") {
        let parts = $tags_str | split row "[[" | skip 1
        for part in $parts {
            let tag = $part | split row "]]" | get 0
            if ($tag | str length) > 0 {
                $tags = ($tags | append $tag)
            }
        }
    } else {
        # Extract comma-separated format
        $tags = ($tags_str | split row ',' | each { |t| $t | str trim })
    }

    $tags
}

def parse_references_from_property [prop: string] {
    if ($prop | str length) == 0 {
        return []
    }

    # Extract [[ref]] format using split
    mut refs = []
    if ($prop | str contains "[[") {
        let parts = $prop | split row "[[" | skip 1
        for part in $parts {
            let ref = $part | split row "]]" | get 0
            if ($ref | str length) > 0 {
                $refs = ($refs | append $ref)
            }
        }
    }
    $refs
}

def build_yaml_frontmatter [data: record] {
    mut fm = "---\n"
    $fm = $fm + $"type: ($data.type)\n"
    $fm = $fm + $"title: ($data.title)\n"
    $fm = $fm + $"created: ($data.created)\n"
    $fm = $fm + $"modified: ($data.modified)\n"
    $fm = $fm + $"status: ($data.status)\n"

    if ($data.tags | length) > 0 {
        let quoted_tags = $data.tags | each { |t| $'"($t)"' }
        let tags_str = $quoted_tags | str join ", "
        $fm = $fm + $"tags: [$tags_str]\n"
    }

    if ($data.relates_to | length) > 0 {
        $fm = $fm + "relates_to:\n"
        for ref in $data.relates_to {
            $fm = $fm + $"  - $ref\n"
        }
    }

    if ($data.depends_on | length) > 0 {
        $fm = $fm + "depends_on:\n"
        for ref in $data.depends_on {
            $fm = $fm + $"  - $ref\n"
        }
    }

    if ($data.implements | length) > 0 {
        $fm = $fm + "implements:\n"
        for ref in $data.implements {
            $fm = $fm + $"  - $ref\n"
        }
    }

    if ($data.extends | length) > 0 {
        $fm = $fm + "extends:\n"
        for ref in $data.extends {
            $fm = $fm + $"  - $ref\n"
        }
    }

    $fm + "---"
}

def convert_logseq_syntax [body: string] {
    # Phase 1: Convert Logseq task markers to standard markdown
    mut converted = $body | str replace -a 'LATER ' ''
    $converted = $converted | str replace -a 'NOW ' ''
    $converted = $converted | str replace -a 'WAITING ' ''
    $converted = $converted | str replace -a 'CANCELLED ' ''

    $converted
}
