// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========

import type { PostgresAccessor } from '../../accessor/postgres.ts'
import { IndexEntry } from '../../cache/index/config.ts'
import { makeReaddir } from '../hierarchy/readdir.ts'
import type { ScopeMatch } from '../hierarchy/scope.ts'
import { compareCodePoints } from '../../utils/sort.ts'
import { listMatviews, listSchemas, listTables, listViews } from './client.ts'
import { detectScope, ENTITY_FILES, KIND_DIRS } from './scope.ts'

async function listRoot(
  accessor: PostgresAccessor,
  _match: ScopeMatch,
): Promise<[string, IndexEntry][]> {
  const schemas = await listSchemas(accessor, accessor.config.schemas)
  const entries: [string, IndexEntry][] = [
    [
      'database.json',
      new IndexEntry({
        id: 'database.json',
        name: 'database.json',
        resourceType: 'postgres/database_json',
        vfsName: 'database.json',
      }),
    ],
  ]
  for (const s of schemas) {
    entries.push([
      s,
      new IndexEntry({ id: s, name: s, resourceType: 'postgres/schema', vfsName: s }),
    ])
  }
  return entries
}

function listSchema(
  _accessor: PostgresAccessor,
  _match: ScopeMatch,
): Promise<[string, IndexEntry][]> {
  // tables/ and views/ exist by construction under every schema, the same
  // way the entity files below do under every entity.
  return Promise.resolve(
    KIND_DIRS.map((name) => [
      name,
      new IndexEntry({ id: name, name, resourceType: 'postgres/kind', vfsName: name }),
    ]),
  )
}

async function listEntities(
  accessor: PostgresAccessor,
  match: ScopeMatch,
): Promise<[string, IndexEntry][]> {
  const schema = match.slots.schema ?? ''
  const kind = match.slots.kind ?? ''
  let names: string[]
  if (kind === 'tables') {
    names = await listTables(accessor, schema)
  } else {
    const views = await listViews(accessor, schema)
    const mviews = await listMatviews(accessor, schema)
    names = [...new Set([...views, ...mviews])].sort(compareCodePoints)
  }
  return names.map((n) => [
    n,
    new IndexEntry({
      id: n,
      name: n,
      resourceType: `postgres/${kind.replace(/s$/, '')}`,
      vfsName: n,
    }),
  ])
}

function listEntityFiles(
  _accessor: PostgresAccessor,
  _match: ScopeMatch,
): Promise<[string, IndexEntry][]> {
  return Promise.resolve(
    ENTITY_FILES.map((name) => [
      name,
      new IndexEntry({ id: name, name, resourceType: 'postgres/entity_file', vfsName: name }),
    ]),
  )
}

export const readdir = makeReaddir<PostgresAccessor>(detectScope, {
  listers: {
    root: listRoot,
    schema: listSchema,
    kind: listEntities,
    entity: listEntityFiles,
  },
})
