<?php
/**
 * Melk_Investor — سرمایه‌گذاران ثروتمند · معیار خرید · هشدار آگهی · کارشناسی
 */
if ( ! defined( 'ABSPATH' ) ) exit;

class Melk_Investor {

    public const DEAL_TYPES = [
        'sale'        => 'خرید / فروش',
        'partnership' => 'مشارکت در ساخت',
        'land_sale'   => 'فروش زمین',
        'pre_sale'    => 'پیش‌فروش',
        'rent'        => 'اجاره',
        'mortgage'    => 'رهن و اجاره',
        'exchange'    => 'معاوضه',
    ];

    public const EXPERT_TYPES = [
        'municipality'    => [ 'label' => 'کارشناس شهرداری', 'role' => 'municipality', 'icon' => '🏛️' ],
        'registry'        => [ 'label' => 'کارشناس ثبت اسناد', 'role' => 'registry', 'icon' => '📜' ],
        'legal'           => [ 'label' => 'وکیل حقوقی', 'role' => 'legal', 'icon' => '⚖️' ],
        'appraisal'       => [ 'label' => 'کارشناس رسمی', 'role' => 'appraisal', 'icon' => '📐' ],
        'melk_specialist' => [ 'label' => 'کارشناس مشترک ملک', 'role' => 'melk_specialist', 'icon' => '👥' ],
        'finance'         => [ 'label' => 'کارشناس مالی', 'role' => 'finance', 'icon' => '💰' ],
    ];

    public static function criteria_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'melk_investment_criteria';
    }

    public static function matches_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'melk_listing_matches';
    }

    public static function expert_req_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'melk_investor_expert_requests';
    }

    public static function profile_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'melk_investor_profiles';
    }

    public static function can_investor( int $uid ): bool {
        return acl_user_is_super_admin( $uid )
            || acl_user_can( $uid, 'melk.investor.manage' )
            || self::_has_role( $uid, 'melk_investor' );
    }

    public static function get_profile( int $user_id ): ?array {
        global $wpdb;
        $t = self::profile_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return null;
        }
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$t} WHERE user_id = %d", $user_id
        ), ARRAY_A );
        return $row ?: null;
    }

    public static function save_profile( int $user_id, array $data ): array {
        global $wpdb;
        $t = self::profile_table();
        $payload = [
            'display_title' => sanitize_text_field( $data['display_title'] ?? '' ),
            'wealth_tier'   => sanitize_key( $data['wealth_tier'] ?? 'premium' ),
            'bio'           => sanitize_textarea_field( $data['bio'] ?? '' ),
            'phone'         => sanitize_text_field( $data['phone'] ?? '' ),
            'updated_at'    => current_time( 'mysql' ),
        ];
        $exists = (int) $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$t} WHERE user_id = %d", $user_id ) );
        if ( $exists ) {
            $wpdb->update( $t, $payload, [ 'user_id' => $user_id ] );
        } else {
            $payload['user_id'] = $user_id;
            $payload['status'] = 'approved';
            $payload['created_at'] = current_time( 'mysql' );
            $wpdb->insert( $t, $payload );
        }
        return [ 'success' => true, 'data' => self::get_profile( $user_id ) ];
    }

    public static function list_criteria( int $user_id ): array {
        global $wpdb;
        $rows = $wpdb->get_results( $wpdb->prepare(
            "SELECT * FROM " . self::criteria_table() . " WHERE user_id = %d ORDER BY id DESC", $user_id
        ), ARRAY_A ) ?: [];
        return array_map( [ __CLASS__, 'fmt_criteria' ], $rows );
    }

    public static function fmt_criteria( array $row ): array {
        foreach ( [ 'deal_types', 'property_types', 'district_ids', 'neighborhood_ids' ] as $k ) {
            $row[ $k ] = json_decode( $row[ $k ] ?? '[]', true ) ?: [];
        }
        $row['alert_active'] = (int) ( $row['alert_active'] ?? 1 ) === 1;
        return $row;
    }

    public static function create_criteria( int $user_id, array $data ): array {
        global $wpdb;
        $title = sanitize_text_field( $data['title'] ?? 'معیار سرمایه‌گذاری' );
        if ( ! $title ) {
            return [ 'success' => false, 'message' => 'عنوان معیار الزامی است' ];
        }
        $wpdb->insert( self::criteria_table(), [
            'user_id'          => $user_id,
            'title'            => $title,
            'deal_types'       => wp_json_encode( self::_arr( $data['deal_types'] ?? [] ) ),
            'property_types'   => wp_json_encode( self::_arr( $data['property_types'] ?? [] ) ),
            'district_ids'     => wp_json_encode( array_map( 'intval', self::_arr( $data['district_ids'] ?? [] ) ) ),
            'neighborhood_ids' => wp_json_encode( array_map( 'intval', self::_arr( $data['neighborhood_ids'] ?? [] ) ) ),
            'min_area_sqm'     => isset( $data['min_area_sqm'] ) && $data['min_area_sqm'] !== '' ? (float) $data['min_area_sqm'] : null,
            'max_area_sqm'     => isset( $data['max_area_sqm'] ) && $data['max_area_sqm'] !== '' ? (float) $data['max_area_sqm'] : null,
            'budget_min'       => isset( $data['budget_min'] ) && $data['budget_min'] !== '' ? (float) $data['budget_min'] : null,
            'budget_max'       => isset( $data['budget_max'] ) && $data['budget_max'] !== '' ? (float) $data['budget_max'] : null,
            'notes'            => sanitize_textarea_field( $data['notes'] ?? '' ),
            'alert_active'     => ! empty( $data['alert_active'] ) ? 1 : 0,
            'created_at'       => current_time( 'mysql' ),
        ] );
        $id = (int) $wpdb->insert_id;
        self::match_all_for_criteria( $id );
        return [ 'success' => true, 'id' => $id ];
    }

    public static function update_criteria( int $id, int $user_id, array $data ): array {
        global $wpdb;
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM " . self::criteria_table() . " WHERE id = %d AND user_id = %d", $id, $user_id
        ), ARRAY_A );
        if ( ! $row ) {
            return [ 'success' => false, 'message' => 'معیار یافت نشد' ];
        }
        $upd = [];
        if ( isset( $data['title'] ) ) {
            $upd['title'] = sanitize_text_field( $data['title'] );
        }
        if ( isset( $data['notes'] ) ) {
            $upd['notes'] = sanitize_textarea_field( $data['notes'] );
        }
        foreach ( [ 'deal_types', 'property_types', 'district_ids', 'neighborhood_ids' ] as $f ) {
            if ( isset( $data[ $f ] ) ) {
                $val = in_array( $f, [ 'district_ids', 'neighborhood_ids' ], true )
                    ? array_map( 'intval', self::_arr( $data[ $f ] ) )
                    : self::_arr( $data[ $f ] );
                $upd[ $f ] = wp_json_encode( $val );
            }
        }
        foreach ( [ 'min_area_sqm', 'max_area_sqm', 'budget_min', 'budget_max' ] as $f ) {
            if ( array_key_exists( $f, $data ) ) {
                $upd[ $f ] = $data[ $f ] !== '' && $data[ $f ] !== null ? (float) $data[ $f ] : null;
            }
        }
        if ( isset( $data['alert_active'] ) ) {
            $upd['alert_active'] = ! empty( $data['alert_active'] ) ? 1 : 0;
        }
        if ( $upd ) {
            $wpdb->update( self::criteria_table(), $upd, [ 'id' => $id ] );
            self::match_all_for_criteria( $id );
        }
        return [ 'success' => true ];
    }

    public static function delete_criteria( int $id, int $user_id ): bool {
        global $wpdb;
        return (bool) $wpdb->delete( self::criteria_table(), [ 'id' => $id, 'user_id' => $user_id ] );
    }

    public static function list_matches( int $user_id, bool $unseen_only = false ): array {
        global $wpdb;
        $mt = self::matches_table();
        $lt = $wpdb->prefix . 'melk_listings';
        $where = 'm.investor_user_id = %d';
        $args  = [ $user_id ];
        if ( $unseen_only ) {
            $where .= ' AND m.seen_at IS NULL';
        }
        return $wpdb->get_results( $wpdb->prepare(
            "SELECT m.*, l.title AS listing_title, l.deal_type, l.property_type, l.price, l.area_sqm,
                    l.district_id, l.neighborhood_id, l.listing_key, l.status AS listing_status,
                    c.title AS criteria_title
             FROM {$mt} m
             INNER JOIN {$lt} l ON l.id = m.listing_id
             LEFT JOIN " . self::criteria_table() . " c ON c.id = m.criteria_id
             WHERE {$where}
             ORDER BY m.created_at DESC LIMIT 100",
            ...$args
        ), ARRAY_A ) ?: [];
    }

    public static function mark_match_seen( int $match_id, int $user_id ): bool {
        global $wpdb;
        return (bool) $wpdb->update(
            self::matches_table(),
            [ 'seen_at' => current_time( 'mysql' ) ],
            [ 'id' => $match_id, 'investor_user_id' => $user_id ]
        );
    }

    public static function match_listing( int $listing_id ): int {
        global $wpdb;
        $listing = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}melk_listings WHERE id = %d", $listing_id
        ), ARRAY_A );
        if ( ! $listing || ( $listing['status'] ?? '' ) !== 'active' ) {
            return 0;
        }
        $criteria = $wpdb->get_results(
            "SELECT * FROM " . self::criteria_table() . " WHERE alert_active = 1",
            ARRAY_A
        ) ?: [];
        $n = 0;
        foreach ( $criteria as $c ) {
            $score = self::score_match( self::fmt_criteria( $c ), $listing );
            if ( $score >= 50 ) {
                self::_upsert_match( (int) $c['id'], $listing_id, (int) $c['user_id'], $score );
                $n++;
            }
        }
        return $n;
    }

    public static function match_all_for_criteria( int $criteria_id ): int {
        global $wpdb;
        $c = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM " . self::criteria_table() . " WHERE id = %d", $criteria_id
        ), ARRAY_A );
        if ( ! $c || ! (int) $c['alert_active'] ) {
            return 0;
        }
        $c = self::fmt_criteria( $c );
        $listings = $wpdb->get_results(
            "SELECT * FROM {$wpdb->prefix}melk_listings WHERE status = 'active' ORDER BY id DESC LIMIT 500",
            ARRAY_A
        ) ?: [];
        $n = 0;
        foreach ( $listings as $l ) {
            if ( self::score_match( $c, $l ) >= 50 ) {
                self::_upsert_match( $criteria_id, (int) $l['id'], (int) $c['user_id'], self::score_match( $c, $l ) );
                $n++;
            }
        }
        return $n;
    }

    public static function score_match( array $criteria, array $listing ): int {
        $score = 0;
        $deal_types = $criteria['deal_types'] ?? [];
        if ( $deal_types && in_array( $listing['deal_type'] ?? '', $deal_types, true ) ) {
            $score += 25;
        } elseif ( ! $deal_types ) {
            $score += 10;
        }
        $prop_types = $criteria['property_types'] ?? [];
        if ( $prop_types && in_array( $listing['property_type'] ?? '', $prop_types, true ) ) {
            $score += 15;
        } elseif ( ! $prop_types ) {
            $score += 5;
        }
        $districts = $criteria['district_ids'] ?? [];
        if ( $districts && ! in_array( (int) ( $listing['district_id'] ?? 0 ), $districts, true ) ) {
            return 0;
        }
        if ( $districts ) {
            $score += 30;
        }
        $neighs = $criteria['neighborhood_ids'] ?? [];
        if ( $neighs && ! in_array( (int) ( $listing['neighborhood_id'] ?? 0 ), $neighs, true ) ) {
            return 0;
        }
        if ( $neighs ) {
            $score += 25;
        }
        $area = (float) ( $listing['area_sqm'] ?? 0 );
        $min_a = (float) ( $criteria['min_area_sqm'] ?? 0 );
        if ( $min_a > 0 && ( $area <= 0 || $area < $min_a ) ) {
            return 0;
        }
        if ( $min_a > 0 && $area >= $min_a ) {
            $score += 15;
        }
        $price = (float) ( $listing['price'] ?? 0 );
        $bmax  = (float) ( $criteria['budget_max'] ?? 0 );
        if ( $bmax > 0 && $price > 0 && $price > $bmax ) {
            return 0;
        }
        if ( $bmax > 0 && $price > 0 ) {
            $score += 10;
        }
        return min( 100, $score );
    }

    private static function _upsert_match( int $criteria_id, int $listing_id, int $investor_user_id, int $score ): void {
        global $wpdb;
        $t = self::matches_table();
        $exists = (int) $wpdb->get_var( $wpdb->prepare(
            "SELECT id FROM {$t} WHERE criteria_id = %d AND listing_id = %d", $criteria_id, $listing_id
        ) );
        if ( $exists ) {
            $wpdb->update( $t, [ 'match_score' => $score ], [ 'id' => $exists ] );
            return;
        }
        $wpdb->insert( $t, [
            'criteria_id'      => $criteria_id,
            'listing_id'       => $listing_id,
            'investor_user_id' => $investor_user_id,
            'match_score'      => $score,
            'created_at'       => current_time( 'mysql' ),
        ] );
    }

    public static function list_experts(): array {
        global $wpdb;
        $out = [];
        foreach ( self::EXPERT_TYPES as $key => $meta ) {
            $role_id = (int) $wpdb->get_var( $wpdb->prepare(
                "SELECT id FROM {$wpdb->prefix}acl_roles WHERE slug = %s", $meta['role']
            ) );
            if ( ! $role_id ) {
                continue;
            }
            $users = $wpdb->get_results( $wpdb->prepare(
                "SELECT u.ID AS id, u.display_name, u.user_login
                 FROM {$wpdb->users} u
                 INNER JOIN {$wpdb->prefix}acl_user_roles ur ON ur.user_id = u.ID AND ur.role_id = %d
                 LIMIT 20",
                $role_id
            ), ARRAY_A ) ?: [];
            foreach ( $users as $u ) {
                $out[] = [
                    'expert_type'  => $key,
                    'expert_label' => $meta['label'],
                    'icon'         => $meta['icon'],
                    'user_id'      => (int) $u['id'],
                    'name'         => $u['display_name'] ?: $u['user_login'],
                    'login'        => $u['user_login'],
                ];
            }
        }
        return $out;
    }

    public static function create_expert_request( int $user_id, array $data ): array {
        global $wpdb;
        $types = self::_arr( $data['expert_types'] ?? [] );
        $subject = sanitize_text_field( $data['subject'] ?? '' );
        if ( ! $types || ! $subject ) {
            return [ 'success' => false, 'message' => 'نوع کارشناس و موضوع الزامی است' ];
        }
        $wpdb->insert( self::expert_req_table(), [
            'user_id'      => $user_id,
            'listing_id'   => ! empty( $data['listing_id'] ) ? (int) $data['listing_id'] : null,
            'match_id'     => ! empty( $data['match_id'] ) ? (int) $data['match_id'] : null,
            'expert_types' => wp_json_encode( $types ),
            'subject'      => $subject,
            'description'  => sanitize_textarea_field( $data['description'] ?? '' ),
            'status'       => 'pending',
            'created_at'   => current_time( 'mysql' ),
        ] );
        return [ 'success' => true, 'id' => (int) $wpdb->insert_id ];
    }

    public static function list_expert_requests( int $user_id, bool $mine_only = true ): array {
        global $wpdb;
        $t = self::expert_req_table();
        $sql = $mine_only
            ? $wpdb->prepare( "SELECT * FROM {$t} WHERE user_id = %d ORDER BY id DESC LIMIT 50", $user_id )
            : "SELECT * FROM {$t} ORDER BY id DESC LIMIT 50";
        $rows = $wpdb->get_results( $sql, ARRAY_A ) ?: [];
        foreach ( $rows as &$r ) {
            $r['expert_types'] = json_decode( $r['expert_types'] ?? '[]', true ) ?: [];
        }
        return $rows;
    }

    public static function respond_expert_request( int $id, int $expert_uid, string $response ): array {
        global $wpdb;
        $wpdb->update( self::expert_req_table(), [
            'status'         => 'answered',
            'expert_user_id' => $expert_uid,
            'response_text'  => sanitize_textarea_field( $response ),
            'answered_at'    => current_time( 'mysql' ),
        ], [ 'id' => $id ] );
        return [ 'success' => true ];
    }

    public static function geo_options(): array {
        global $wpdb;
        $pre = $wpdb->prefix;
        return [
            'districts'     => $wpdb->get_results( "SELECT id, name, code FROM {$pre}gis_districts ORDER BY id", ARRAY_A ) ?: [],
            'neighborhoods' => $wpdb->get_results( "SELECT id, name, district_id FROM {$pre}gis_neighborhoods ORDER BY district_id, id", ARRAY_A ) ?: [],
        ];
    }

    public static function unseen_count( int $user_id ): int {
        global $wpdb;
        $t = self::matches_table();
        return (int) $wpdb->get_var( $wpdb->prepare(
            "SELECT COUNT(*) FROM {$t} WHERE investor_user_id = %d AND seen_at IS NULL", $user_id
        ) );
    }

    private static function _arr( $v ): array {
        if ( is_string( $v ) ) {
            $v = array_filter( array_map( 'trim', explode( ',', $v ) ) );
        }
        return is_array( $v ) ? array_values( $v ) : [];
    }

    private static function _has_role( int $user_id, string $slug ): bool {
        global $wpdb;
        return (bool) (int) $wpdb->get_var( $wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->prefix}acl_user_roles ur
             INNER JOIN {$wpdb->prefix}acl_roles r ON r.id = ur.role_id
             WHERE ur.user_id = %d AND r.slug = %s",
            $user_id, $slug
        ) );
    }
}
