<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/layout :: head('보호 상태')}"></head>
<body>
<nav th:replace="~{fragments/layout :: nav}"></nav>
<main class="container py-4">
  <div class="page-title">
    <h1>보호 상태</h1>
    <details class="explanation-details">
      <summary>도움말</summary>
      <p>행 접근 규칙 화면에서 만든 사용자·그룹·역할·행 규칙을 Oracle VPD가 실제 TABLE/VIEW에 적용하도록 연결합니다. Policy는 어느 객체의 어떤 SQL에 어떤 Filter function을 붙일지 정하고, 실제 허용 조건은 행 접근 규칙과 Filter가 계산합니다.</p>
      <p>이 화면은 <strong>행 접근 정책</strong>만 확인합니다. 컬럼 원문/마스킹 적용 상태는 <a href="/masking-rules">컬럼 마스킹</a>의 ASO/Data Redaction 상태에서 확인하세요.</p>
    </details>
  </div>

  <div class="alert alert-warning" th:if="${runtimeError}">
    <strong th:text="${runtimeError.title()}">조회할 수 없습니다.</strong>
    <span th:text="${runtimeError.message()}">message</span>
  </div>
  <div class="alert alert-success" th:if="${successMessage}" th:text="${successMessage}">등록되었습니다.</div>
  <div class="alert alert-danger" th:if="${errorMessage}" th:text="${errorMessage}">처리할 수 없습니다.</div>

  <section class="content-band">
    <div class="section-heading">
      <div>
        <h2>보호 대상</h2>
        <p class="section-subtitle">행 접근 정책 적용과 검증 준비 상태를 확인합니다.</p>
        <details class="explanation-details">
          <summary>객체 상태 항목 설명 보기</summary>
          <p>Oracle VPD 정책이 붙었는지, 행 접근 규칙과 검증 경로가 준비됐는지 한곳에서 확인합니다. 아래 기본 적용에서는 객체만 선택하면 됩니다.</p>
        </details>
      </div>
      <span class="badge text-bg-secondary" th:text="${#lists.size(vpdTargets)}">0</span>
    </div>
    <form method="get" action="/vpd-policies" class="inline-form mb-3">
      <label>
        Schema
        <input class="form-control form-control-sm" name="schemaOwner" list="vpd-schema-owner-options"
               th:value="${selectedSchemaOwner}" placeholder="관리 대상 스키마 또는 직접 입력">
      </label>
      <button class="btn btn-sm rw-btn-secondary" type="submit">조회</button>
    </form>
    <datalist id="vpd-schema-owner-options">
      <option value="">관리 대상 스키마</option>
      <option th:each="owner : ${formOptions.schemaOwners()}" th:value="${owner}"></option>
    </datalist>
    <div class="vpd-target-controls" data-vpd-target-controls th:if="${!#lists.isEmpty(vpdTargets)}">
      <label>
        Object 검색
        <input class="form-control form-control-sm" type="search" placeholder="예: BOARD, CUSTOMER"
               data-vpd-target-search>
      </label>
      <label>
        Type
        <select class="form-select form-select-sm" data-vpd-target-type>
          <option value="">전체</option>
          <option value="TABLE">TABLE</option>
          <option value="VIEW">VIEW</option>
        </select>
      </label>
      <label>
        VPD 상태
        <select class="form-select form-select-sm" data-vpd-target-vpd>
          <option value="">전체</option>
          <option value="true">VPD 적용됨</option>
          <option value="false">미적용</option>
        </select>
      </label>
      <label>
        권한 등록
        <select class="form-select form-select-sm" data-vpd-target-protected>
          <option value="">전체</option>
          <option value="true">등록됨</option>
          <option value="false">미등록</option>
        </select>
      </label>
      <label>
        표시
        <select class="form-select form-select-sm" data-vpd-target-page-size>
          <option value="25">25</option>
          <option value="50" selected>50</option>
          <option value="100">100</option>
          <option value="ALL">전체</option>
        </select>
      </label>
      <label class="form-check vpd-support-toggle">
        <input class="form-check-input" type="checkbox" data-vpd-target-include-support>
        <span class="form-check-label">운영 지원 테이블 포함</span>
      </label>
      <button class="btn btn-sm rw-btn-secondary" type="button" data-vpd-target-reset>초기화</button>
      <div class="vpd-target-count" aria-live="polite">
        표시 <strong data-vpd-target-visible>0</strong>
        / 일치 <strong data-vpd-target-matched>0</strong>
        / 전체 <span data-vpd-target-total th:text="${#lists.size(vpdTargets)}">0</span>
      </div>
    </div>
    <div class="table-responsive">
      <table class="table table-sm align-middle">
        <thead>
        <tr>
          <th>Object</th>
          <th>대상 설명</th>
          <th>Type</th>
          <th>VPD 상태</th>
          <th>Policy</th>
          <th>Filter</th>
          <th>운영 권한 테이블</th>
          <th>검증용 ORDS 경로</th>
        </tr>
        </thead>
        <tbody data-vpd-target-body>
        <th:block th:each="target, iter : ${vpdTargets}">
        <tr data-vpd-target-row
            th:attr="data-object=${target.objectDisplayName()},
                     data-object-name=${target.objectName()},
                     data-object-type=${target.objectType()},
                     data-vpd-applied=${target.vpdApplied()},
                     data-protected-object=${target.protectedObject()}">
          <td><code th:text="${target.objectDisplayName()}">ADMIN.TABLE</code></td>
          <td th:text="${target.description()} ?: '설명 없음'">조회 대상 설명</td>
          <td th:text="${target.objectType()}">TABLE</td>
          <td>
            <span class="badge"
                  th:classappend="${target.vpdApplied()} ? ' text-bg-success' : ' text-bg-secondary'"
                  th:text="${target.vpdApplied()} ? 'VPD 적용됨' : '미적용'">미적용</span>
          </td>
          <td>
            <span th:if="${target.vpdApplied()}" th:text="${target.policyNames()}">POLICY</span>
            <span th:unless="${target.vpdApplied()}" class="text-muted">-</span>
          </td>
          <td>
            <button th:if="${target.vpdApplied()}"
                    class="btn btn-sm btn-outline-secondary policy-function-button"
                    type="button"
                    aria-expanded="false"
                    data-filter-toggle="true"
                    data-toggle-default-text="Filter 이름을 클릭하면 policy/filter source가 표시됩니다."
                    data-toggle-loading-text="policy/filter source를 조회하는 중입니다."
                    th:hx-get="@{/vpd-policies/object-filter-detail(objectOwner=${target.owner()},objectName=${target.objectName()})}"
                    th:hx-target="${'#target-filter-detail-' + iter.index}"
                    hx-swap="innerHTML">
              <code th:text="${target.filterNames()}">ADMIN.FILTER</code>
            </button>
            <span th:unless="${target.vpdApplied()}" class="text-muted">-</span>
          </td>
          <td>
            <span class="badge"
                  th:classappend="${target.protectedObject()} ? ' text-bg-primary' : ' text-bg-light'"
                  th:text="${target.protectedObject()} ? '등록됨' : '미등록'">미등록</span>
          </td>
          <td>
            <code th:if="${target.ordsPath()}" th:text="${target.ordsPath()}">cb-ords/path</code>
            <span th:unless="${target.ordsPath()}" class="text-muted">검증 경로 미등록</span>
          </td>
        </tr>
        <tr th:if="${target.vpdApplied()}" data-vpd-target-detail>
          <td colspan="8" class="policy-source-cell">
            <div th:id="${'target-filter-detail-' + iter.index}" class="text-muted small">
              Filter 이름을 클릭하면 policy/filter source가 표시됩니다.
            </div>
          </td>
        </tr>
        </th:block>
        <tr th:if="${#lists.isEmpty(vpdTargets)}">
          <td colspan="8" class="text-muted">
            <span th:if="${selectedSchemaOwner != null && selectedSchemaOwner != ''}"
                  th:text="${selectedSchemaOwner + ' 스키마에서 현재 DB 연결 사용자로 조회 가능한 TABLE/VIEW가 없습니다. 스키마명, ALL_OBJECTS 조회 권한, 객체 권한을 확인하세요.'}">
              선택한 스키마에서 조회 가능한 TABLE/VIEW가 없습니다.
            </span>
            <span th:unless="${selectedSchemaOwner != null && selectedSchemaOwner != ''}">
              조회 가능한 TABLE/VIEW가 없습니다. DB 연결 사용자 권한과 스키마 객체를 확인하세요.
            </span>
          </td>
        </tr>
        </tbody>
      </table>
    </div>
  </section>

  <section class="content-band">
    <div class="section-heading">
      <div>
        <span class="architecture-kicker">권장 · 일반 작업</span>
        <h2>객체 하나에 권한체계 연결</h2>
        <p class="section-subtitle">객체를 선택하면 표준 동적 정책을 기본값으로 적용합니다.</p>
        <details class="explanation-details">
          <summary>기본 적용 내용 보기</summary>
          <p>객체만 선택하면 표준 동적 함수, SELECT 정책, 즉시 활성화를 서버가 안전한 기본값으로 적용합니다.</p>
        </details>
      </div>
    </div>
    <form method="post" action="/vpd-policies/default" class="form-grid default-vpd-form">
      <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
      <label>
        보호할 TABLE/VIEW
        <select class="form-select" name="objectKey" required>
          <option th:each="target : ${vpdTargets}"
                  th:value="${target.objectDisplayName()}"
                  th:text="${target.objectDisplayName() + ' · ' + target.objectType() + (target.vpdApplied() ? ' · 이미 VPD 있음' : ' · 연결 필요')}"></option>
        </select>
      </label>
      <aside class="default-policy-summary">
        <strong>자동 적용 내용</strong>
        <span>권한체계 동적 조회 · SELECT 보호 · 즉시 활성화 · 권한 없음은 차단</span>
      </aside>
      <button class="btn rw-btn-primary" type="submit">권한체계 자동 적용</button>
    </form>
  </section>

  <section class="content-band">
    <details>
      <summary class="bulk-apply-summary">고급: 여러 객체에 권한체계 일괄 연결</summary>
      <div class="advanced-guidance mt-3">
        <strong>언제 사용하나요?</strong>
        <p>한 스키마의 TABLE/VIEW가 모두 같은 권한체계를 사용해야 하고, 대상 목록을 먼저 검토했을 때만 사용합니다. 기존 policy가 있는 객체는 건너뜁니다.</p>
      </div>
      <form method="post" action="/vpd-policies/bulk" class="form-grid mt-3">
        <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
        <input type="hidden" name="enabled" value="true">
        <label>
          Schema
          <select class="form-select" name="schemaOwner" required>
            <option th:each="owner : ${formOptions.schemaOwners()}" th:value="${owner}" th:text="${owner}"></option>
          </select>
        </label>
        <div>
          Object Types
          <div class="checkbox-row">
            <label class="form-check">
              <input class="form-check-input" type="checkbox" name="includeTables" value="true" checked>
              <span class="form-check-label">TABLE</span>
            </label>
            <label class="form-check">
              <input class="form-check-input" type="checkbox" name="includeViews" value="true" checked>
              <span class="form-check-label">VIEW</span>
            </label>
          </div>
        </div>
        <p class="text-muted small span-2 mb-0">모든 대상에 표준 <code>CB_PERMISSION_SELECT_POLICY</code>와 <code>CB_AGENT_DOC_VPD_FILTER</code>를 적용합니다. 별도 predicate가 필요하면 관리자 메뉴의 고급 접근 조건 가이드를 먼저 확인하세요.</p>
        <button class="btn rw-btn-primary" type="submit">선택 스키마에 권한체계 일괄 연결</button>
      </form>
    </details>
  </section>

  <section class="content-band">
    <div class="section-heading">
      <div>
        <h2>현재 적용된 DB 보호 정책</h2>
        <p class="section-subtitle">“권한체계 자동” 표시는 권한 규칙 변경을 요청 시점에 동적으로 반영하는 표준 정책입니다.</p>
      </div>
      <span class="badge text-bg-secondary" th:text="${#lists.size(policies)}">0</span>
    </div>

    <div class="table-responsive">
      <table class="table table-sm table-striped align-middle">
        <thead>
        <tr>
          <th>Object</th>
          <th>Policy</th>
          <th>Filter</th>
          <th>Statements</th>
          <th>Status</th>
          <th>Type</th>
          <th>Options</th>
          <th>이 policy가 하는 일</th>
          <th>Explain</th>
        </tr>
        </thead>
        <tbody>
        <th:block th:each="policy, iter : ${policies}">
        <tr>
          <td>
            <strong th:text="${policy.objectDisplayName()}">ADMIN.TABLE</strong>
            <div class="text-muted small" th:text="${policy.policyGroup()}">SYS_DEFAULT</div>
          </td>
          <td>
            <button class="btn btn-sm btn-outline-secondary policy-function-button"
                    type="button"
                    th:hx-get="@{/vpd-policies/policy-detail(objectOwner=${policy.objectOwner()},objectName=${policy.objectName()},policyName=${policy.policyName()})}"
                    th:hx-target="${'#policy-source-' + iter.index}"
                    hx-swap="innerHTML">
              <code th:text="${policy.policyName()}">POLICY</code>
            </button>
          </td>
          <td>
            <button class="btn btn-sm btn-outline-secondary policy-function-button"
                    type="button"
                    th:hx-get="@{/vpd-policies/function-source(owner=${policy.functionOwner()},packageName=${policy.packageName()},functionName=${policy.functionName()})}"
                    th:hx-target="${'#policy-source-' + iter.index}"
                    hx-swap="innerHTML">
              <code th:text="${policy.functionDisplayName()}">OWNER.FUNC</code>
            </button>
            <div class="text-muted small">클릭하면 filter source를 봅니다.</div>
            <div class="small mt-1" th:text="${filterDescriptions[policy.functionOwner() + '|' + policy.functionName()]}">
              Filter가 반환하는 predicate 설명
            </div>
            <span class="badge text-bg-primary" th:if="${policy.permissionSystemDefault()}">권한체계 자동</span>
            <span class="badge text-bg-warning" th:unless="${policy.permissionSystemDefault()}">별도 Filter</span>
          </td>
          <td th:text="${policy.statementTypes()} ?: '-'">SELECT</td>
          <td>
            <span class="badge"
                  th:classappend="${policy.enabled() == 'YES'} ? ' text-bg-success' : ' text-bg-secondary'"
                  th:text="${policy.enabled()}">YES</span>
          </td>
          <td th:text="${policy.policyType()}">DYNAMIC</td>
          <td>
            <span>Check: <strong th:text="${policy.checkOption()}">NO</strong></span>
            <span class="ms-2">Static: <strong th:text="${policy.staticPolicy()}">NO</strong></span>
            <span class="ms-2">Long: <strong th:text="${policy.longPredicate()}">NO</strong></span>
          </td>
          <td>
            <form method="post" action="/vpd-policies/description" class="inline-form">
              <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
              <input type="hidden" name="objectOwner" th:value="${policy.objectOwner()}">
              <input type="hidden" name="objectName" th:value="${policy.objectName()}">
              <input type="hidden" name="policyName" th:value="${policy.policyName()}">
              <input class="form-control form-control-sm" name="description" maxlength="500"
                     th:value="${policyDescriptions[policy.objectDisplayName() + '|' + policy.policyName()]}"
                     placeholder="대상과 적용 목적을 짧게 설명">
              <button class="btn btn-sm btn-outline-primary" type="submit">저장</button>
            </form>
          </td>
          <td>
            <div class="action-stack">
              <button class="btn btn-sm rw-btn-primary"
                    type="button"
                    th:hx-get="@{/vpd-policies/policy-explanation(objectOwner=${policy.objectOwner()},objectName=${policy.objectName()},policyName=${policy.policyName()})}"
                    th:hx-target="${'#policy-source-' + iter.index}"
                    th:hx-indicator="${'#policy-loading-' + iter.index}"
                    hx-swap="innerHTML">
                LLM 설명
              </button>
              <span th:id="${'policy-loading-' + iter.index}" class="htmx-indicator loading-pill">
                <span class="loading-spinner" aria-hidden="true"></span>
                분석 중
              </span>
            </div>
          </td>
        </tr>
        <tr>
          <td colspan="9" class="policy-source-cell">
            <div th:id="${'policy-source-' + iter.index}" class="text-muted small">
              Policy, Filter, LLM 설명을 클릭하면 상세 내역이 표시됩니다.
            </div>
          </td>
        </tr>
        </th:block>
        <tr th:if="${#lists.isEmpty(policies)}">
          <td colspan="9" class="text-muted">
            등록된 TABLE/VIEW에 적용된 VPD policy가 없습니다. 보호 객체 등록 상태와 DB policy 적용 상태를 확인하세요.
          </td>
        </tr>
        </tbody>
      </table>
    </div>
  </section>
</main>
</body>
</html>
