<?php
/**
 * System uprawnień KSeF — per-feature capabilities + UI w Ustawieniach.
 *
 * Standardowe role WP (administrator, shop_manager) dostają wszystkie caps
 * przy instalacji. Admin może je odebrać poszczególnym rolom w panelu
 * Ustawienia → Uprawnienia. Wszystkie strony KSeF + endpointy wewnętrzne
 * sprawdzają per-feature cap zamiast 'manage_woocommerce'.
 *
 * Capabilities:
 *  - ksef_view_outgoing            — dostęp do listy Faktury sprzedaży
 *  - ksef_view_incoming            — dostęp do listy Faktury zakupu
 *  - ksef_create_invoice           — możliwość wystawiania (Wystaw fakturę)
 *  - ksef_view_external_invoices   — czy widzi faktury z source='ksef_pulled'
 *  - ksef_view_contractors         — Kontrahenci
 *  - ksef_view_reports             — Raporty
 *  - ksef_view_monitoring          — Monitoring
 *  - ksef_view_settings            — Ustawienia + Kredencjały
 *
 * @package KSEF\WordPress
 */

declare(strict_types=1);

namespace KSEF\WordPress;

final class Capabilities {

	public const ALL_CAPS = [
		'ksef_view_outgoing'          => [ 'label' => 'Faktury sprzedaży',          'desc' => 'Dostęp do listy faktur sprzedaży.' ],
		'ksef_view_incoming'          => [ 'label' => 'Faktury zakupu',             'desc' => 'Dostęp do listy faktur zakupu.' ],
		'ksef_create_invoice'         => [ 'label' => 'Wystawianie faktur',         'desc' => 'Możliwość wystawiania faktur (formularz „Wystaw fakturę").' ],
		'ksef_view_external_invoices' => [ 'label' => 'Faktury pobrane z KSeF',     'desc' => 'Pokazuje też faktury sprzedaży wystawione poza wtyczką (pobrane z KSeF). Bez tego widzi tylko faktury wystawione w sklepie.' ],
		'ksef_view_contractors'       => [ 'label' => 'Kontrahenci',                'desc' => 'Dostęp do bazy kontrahentów.' ],
		'ksef_view_reports'           => [ 'label' => 'Raporty',                    'desc' => 'Dostęp do raportów sprzedaży/zakupów.' ],
		'ksef_view_monitoring'        => [ 'label' => 'Monitoring',                 'desc' => 'Dostęp do monitoringu KSeF.' ],
		'ksef_view_settings'          => [ 'label' => 'Ustawienia + Kredencjały',   'desc' => 'Pełen dostęp do ustawień, tokenów KSeF i uprawnień.' ],
	];

	public const DEFAULT_ROLES_FULL = [ 'administrator' ];

	/**
	 * Wywołane przy aktywacji + przy bootstrapie (idempotentne).
	 * - Administrator: dostaje wszystkie KSeF cap.
	 * - Pozostałe role (w tym shop_manager): nie dostają nic; admin musi
	 *   przyznać im dostęp ręcznie w Ustawienia → Uprawnienia.
	 * - Cleanup: jeśli wcześniejsza wersja wtyczki dodała KSeF cap do
	 *   shop_manager (do v1.6.0 było tak domyślnie), usuwamy je.
	 */
	public static function ensure_default_caps(): void {
		foreach ( self::DEFAULT_ROLES_FULL as $role_name ) {
			$role = get_role( $role_name );
			if ( ! $role ) {
				continue;
			}
			foreach ( array_keys( self::ALL_CAPS ) as $cap ) {
				if ( ! $role->has_cap( $cap ) ) {
					$role->add_cap( $cap );
				}
			}
		}
		// Jednorazowy cleanup po zmianie polityki (poprzednia wersja dodawała
		// caps do shop_manager). Flaga zapobiega ponownemu usunięciu po tym,
		// jak admin świadomie nada cap shop_managerowi w UI.
		if ( ! get_option( 'ksef_caps_v160_cleanup', false ) ) {
			$shop = get_role( 'shop_manager' );
			if ( $shop ) {
				foreach ( array_keys( self::ALL_CAPS ) as $cap ) {
					if ( $shop->has_cap( $cap ) ) {
						$shop->remove_cap( $cap );
					}
				}
			}
			update_option( 'ksef_caps_v160_cleanup', true, false );
		}
	}

	/**
	 * Override domyślnego mapowania w current_user_can — pozwala adminowi
	 * dynamicznie zmieniać caps per-rola/per-user przez UI bez przebudowy bazy.
	 *
	 * Lookup w wp_options: ksef_role_caps = [ role_name => [ cap => true|false ] ]
	 *                      ksef_user_caps = [ user_id => [ cap => true|false ] ]  (override roli)
	 */
	public static function register(): void {
		self::ensure_default_caps();
		add_filter( 'user_has_cap', [ self::class, 'filter_user_has_cap' ], 10, 3 );
	}

	public static function filter_user_has_cap( array $allcaps, array $caps, array $args ): array {
		$user_id = isset( $args[1] ) ? (int) $args[1] : 0;
		if ( $user_id <= 0 ) {
			return $allcaps;
		}

		$user_overrides = (array) get_option( 'ksef_user_caps', [] );
		$role_overrides = (array) get_option( 'ksef_role_caps', [] );
		$user = get_user_by( 'id', $user_id );
		if ( ! $user ) {
			return $allcaps;
		}

		// Najpierw przykładamy override roli (admin zaznaczył co rola może).
		foreach ( (array) $user->roles as $role_name ) {
			if ( empty( $role_overrides[ $role_name ] ) || ! is_array( $role_overrides[ $role_name ] ) ) {
				continue;
			}
			foreach ( array_keys( self::ALL_CAPS ) as $cap ) {
				if ( array_key_exists( $cap, $role_overrides[ $role_name ] ) ) {
					$allcaps[ $cap ] = (bool) $role_overrides[ $role_name ][ $cap ];
				}
			}
		}

		// Per-user override (wyższy priorytet niż rola).
		if ( ! empty( $user_overrides[ $user_id ] ) && is_array( $user_overrides[ $user_id ] ) ) {
			foreach ( array_keys( self::ALL_CAPS ) as $cap ) {
				if ( array_key_exists( $cap, $user_overrides[ $user_id ] ) ) {
					$allcaps[ $cap ] = (bool) $user_overrides[ $user_id ][ $cap ];
				}
			}
		}

		return $allcaps;
	}

	/**
	 * Czy user widzi faktury z source='ksef_pulled' (poza wtyczką)?
	 * Helper do użycia w WHERE list — admin może odebrać tę widoczność osobno.
	 */
	public static function can_view_external(): bool {
		return current_user_can( 'ksef_view_external_invoices' );
	}
}
